<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2russianfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>SimpleCoding.org</title>
	
	<link>http://www.simplecoding.org</link>
	<description>Блог о программировании</description>
	<lastBuildDate>Fri, 27 Jan 2012 18:27:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/simplecoding" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="simplecoding" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">simplecoding</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bloglines.com/sub/http://feeds.feedburner.com/simplecoding" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://lenta.yandex.ru/settings.xml?name=feed&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fsimplecoding" src="http://lenta.yandex.ru/i/addfeed.gif">?????? ? ??????.?????</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pusk.ru/#A:Rfeed=http://feeds.feedburner.com/simplecoding" src="http://blog.pusk.ru/wp-includes/images/rss_icon_neutral.png">Subscribe with pusk.ru</feedburner:feedFlare><item>
		<title>WordPress: простой способ отлючить трекбеки для части постов (без плагинов)</title>
		<link>http://www.simplecoding.org/wordpress-prostoj-sposob-otlyuchit-trekbeki-dlya-chasti-postov-bez-plaginov.html</link>
		<comments>http://www.simplecoding.org/wordpress-prostoj-sposob-otlyuchit-trekbeki-dlya-chasti-postov-bez-plaginov.html#comments</comments>
		<pubDate>Sat, 21 Jan 2012 14:46:53 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1259</guid>
		<description><![CDATA[С недавних пор этот блог опять стали одолевать спамеры. Не знаю с чем это связано, больше года всё было относительно спокойно. Проскакивало по несколько спамерских комментариев в неделю, явно написанных людьми, а не ботами, и всё. А тут по 10-20 требкеков в день. Удалить их, конечно, не сложно, но надоедает и раздражает, к тому же [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1260" class="wp-caption alignnone" style="width: 275px"><img src="http://www.simplecoding.org/wp-content/uploads/2012/01/wordpress_block_trackback.png" alt="wordpress block trackback" title="wordpress block trackback" width="265" height="229" class="size-full wp-image-1260" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>С недавних пор этот блог опять стали одолевать спамеры. Не знаю с чем это связано, больше года всё было относительно спокойно. Проскакивало по несколько спамерских комментариев в неделю, явно написанных людьми, а не ботами, и всё. А тут по 10-20 требкеков в день. Удалить их, конечно, не сложно, но надоедает и раздражает, к тому же трекбеки явно ставились автоматически, т.е. спамер своё время на них не тратил.</p>
<p>Вообще я не сторонник отключения каких-либо каналов общения. В теории трекбеки сильно упрощают создание связей между блогами. Но на практике получается, что нормальные требкеки приходят к более-менее новым постам, а спамерские – обычно ко всем подряд.</p>
<p>Поэтому я решил закрыть трекбеки для всех постов старше 2-х месяцев. Ставить специальный плагин для решения этой задачи нет никакой необходимости, всё можно сделать с помощью несложного <strong>SQL запроса и cron&#039;а</strong>.<br />
<span id="more-1259"></span></p>
<h2>Теория</h2>
<p>В WordPress все посты хранятся в таблице <code>wp_posts</code> (префикс <code>wp_</code> может быть другим). В этой таблице есть поле <code>ping_status</code>, которому можно присвоить одно из двух значений: «open» или «closed». Как несложно догадаться по названию, значение «closed» отключает трекбеки к данном посту.</p>
<p>Теперь нужно определиться с датами. MySQL поддерживает довольно много <a href="http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html">функций для работы со временем и датами</a>. Нам потребуются:<br />
1) <code>CURDATE</code> – возвращает текущую дату;<br />
2) <code>DATE_SUB</code> – вычитает даты;<br />
и выражение <code>INTERVAL ... DAY</code> – позволяет указать интервал с заданным количеством дней.</p>
<p>Дата последнего изменения поста хранится в поле <code>post_modified</code> (таблицы <code>wp_posts</code>).</p>
<h2>Формируем запрос</h2>
<pre class="brush: sql; gutter: true; first-line: 1; highlight: []; html-script: false">UPDATE wp_posts SET ping_status=&quot;closed&quot; WHERE post_modified &lt; DATE_SUB(CURDATE(), INTERVAL 60 DAY)</pre>
<p>Как видите, это обычный UPDATE запрос, который установит полю <code>ping_status</code> значение «closed» для всех записей у которые последний раз обновлялись более 60-ти дней назад.</p>
<p>Кстати, аналогичным способом можно закрыть и комментарии. Для этого нужно установить значение «closed» для поля «comment_status».</p>
<h2>Остаётся настроить периодический запуск этого запроса</h2>
<p>Удобнее всего для этого использовать cron. Тут потребуются хотя бы базовые навыки работы с панелью управления хостингом. В большинстве панелей в меню находится ссылка на страницу cron, а для создания задачи нужно заполнить небольшую форму. При этом необходимо указать два обязательных параметра – команду, которую будет выполнять cron, и периодичность её выполнения.</p>
<p>В данном случае команда может выглядеть следующим образом.</p>
<pre class="brush: bash; gutter: true; first-line: 1; highlight: []; html-script: false">mysql --default-character-set=utf8 --user=user_name --password=user_password db_name &lt; path_to/block_trackbacks.sql</pre>
<p>Здесь <code>block_trackbacks.sql</code> – имя файла в котором записан наш запрос.</p>
<p>Периодичность выполнения можно указать – 1 раз в день. Принципиальной роли, в данном случае, она не играет.</p>
<h2>Результаты</h2>
<p>Как и следовало ожидать, работает данный метод очень неплохо. Количество спама в трекбеках снизилось практически до нуля <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  И, обратите внимание, данный способ подходит для любой CMS, главное, найти какое поле отвечает за отключение трекбеков.</p>
<p><strong>Успехов!</strong></p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/0aQlpMun8I4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/wordpress-prostoj-sposob-otlyuchit-trekbeki-dlya-chasti-postov-bez-plaginov.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CSS: оформление скроллбара в стиле Gmail</title>
		<link>http://www.simplecoding.org/css-oformlenie-skrollbara-v-stile-gmail.html</link>
		<comments>http://www.simplecoding.org/css-oformlenie-skrollbara-v-stile-gmail.html#comments</comments>
		<pubDate>Sat, 14 Jan 2012 19:30:05 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Web дизайн]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1252</guid>
		<description><![CDATA[Сегодня мы рассмотрим небольшой пример оформления скроллбара для браузеров на движке WebKit (Chrome, Safari). Сразу хочу сказать, что я не сторонник изменения внешнего вида скролла, всё-таки это стандартный элемент управления и большинство пользователей привыкли к его виду. Злоупотребление возможностью его изменения может усложнить работу с сайтом. Тем не менее, в некоторых случаях создание собственного дизайна [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1253" class="wp-caption alignnone" style="width: 230px"><img src="http://www.simplecoding.org/wp-content/uploads/2012/01/gmail-scroll.png" alt="gmail scrollbar" title="gmail scrollbar" width="220" height="208" class="size-full wp-image-1253" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Сегодня мы рассмотрим небольшой пример <strong>оформления скроллбара для браузеров на движке WebKit</strong> (Chrome, Safari).</p>
<p>Сразу хочу сказать, что я не сторонник изменения внешнего вида скролла, всё-таки это стандартный элемент управления и большинство пользователей привыкли к его виду. Злоупотребление возможностью его изменения может усложнить работу с сайтом.</p>
<p>Тем не менее, в некоторых случаях создание собственного дизайна для скроллбара полностью оправдано. Возьмем в качестве примера структуру страницы Gmail.<br />
<span id="more-1252"></span></p>
<div id="attachment_1254" class="wp-caption alignnone" style="width: 460px"><img src="http://www.simplecoding.org/wp-content/uploads/2012/01/gmail-window.png" alt="gmail-window" title="gmail-window" width="450" height="327" class="size-full wp-image-1254" /><p class="wp-caption-text"> </p></div>
<p>Видите, скроллбар находится внутри страницы, т.е. логично, что его внешний вид должен соответствовать дизайну всей страницы. Ведь во многих случаях в web интерфейсах используется нестандартное оформление кнопок, чекбоксов, ползунков и других элементов управления.</p>
<h2>Теперь рассмотрим, каким образом можно изменить внешний вид скролла</h2>
<p>Движок WebKit поддерживает несколько CSS псевдоклассов, которые определяют оформление различных областей скроллбара. Взгляните на следующий рисунок.</p>
<div id="attachment_1255" class="wp-caption alignnone" style="width: 460px"><img src="http://www.simplecoding.org/wp-content/uploads/2012/01/scroll-default.png" alt="scroll-default" title="scroll-default" width="450" height="204" class="size-full wp-image-1255" /><p class="wp-caption-text"> </p></div>
<p>Как видите, все псевдоклассы имеют префикс <code>-webkit-</code>.<br />
Кроме перечисленных на картинке, есть ещё два псевдокласса:<br />
<code>::-webkit-scrollbar-corner</code> – отвечает за оформление квадрата в месте соприкосновения вертикального и горизонтального скролла;<br />
<code>::-webkit-resizer</code> – используется для скроллбаров текстовой области, размеры которой можно изменять.</p>
<p>Также, вместе с этими классами можно использовать различные псевдоэлементы.</p>
<p>Обычные <code>:enabled</code>, <code>:disabled</code>, <code>:hover</code> и <code>:active</code> и специальные:</p>
<p><code>:horizontal</code> – применяется для частей скроллбара, которые расположены горизонтально;</p>
<p><code>:vertical</code> – применяется для частей скроллбара, которые расположены вертикально;</p>
<p><code>:decrement</code> – применяется к участкам полосы прокрутки и кнопкам при перемещении окна просмотра вверх или влево;</p>
<p><code>:increment</code> – применяется к участкам полосы прокрутки и кнопкам при перемещении окна просмотра вниз или вправо;</p>
<p><code>:start</code> – применяется к кнопкам и участкам полосы прокрутки. Показывает находится ли объект выше (левее) ползунка;</p>
<p><code>:end</code> – применяется к кнопкам и участкам полосы прокрутки. Показывает находится ли объект ниже (правее) ползунка;</p>
<p><code>:double-button</code> – применяется к кнопкам и участкам полосы прокрутки. Используется для того, чтобы определить, является ли кнопка частью двойной кнопки, расположенной на одном из концов полосы прокрутки. Для полосы прокрутки этот псевдокласс показывает граничит ли она с двойной кнопкой;</p>
<p><code>:single-button</code> – применяется к кнопкам и участкам полосы прокрутки. Используется для того, чтобы определить, является ли кнопка одинарной. Для полосы прокрутки этот псевдокласс показывает граничит ли она с одинарной кнопкой;</p>
<p><code>:no-button</code> – применяется к участкам полосы прокрутки и показывает, касается ли она края скроллбара (например, если нет кнопок на краях скроллбара);</p>
<p><code>:corner-present</code> – применяется к участкам полосы прокрутки и показывает, присутствует ли угловая область скроллбара (квадрат на стыке горизонтального и вертикального скроллбаров);</p>
<p><code>:window-inactive</code> – применяется ко всем элементам скроллбара и показывает является ли окно к которому относится данный скроллбар активным.</p>
<h2>Переходим к нашему примеру</h2>
<p>В скроллбаре, который используется в Gmail, нет кнопок вверх-вниз, а ползунок представляет собой обычный прямоугольник серого цвета. При наведении курсора на скроллбар, подсвечивается полоса прокрутки.</p>
<div id="attachment_1256" class="wp-caption alignnone" style="width: 26px"><img src="http://www.simplecoding.org/wp-content/uploads/2012/01/gmail-like-scroll.png" alt="gmail-like-scroll" title="gmail-like-scroll" width="16" height="101" class="size-full wp-image-1256" /><p class="wp-caption-text"> </p></div>
<p><strong>Займёмся оформлением.</strong></p>
<p>Для начала, зададим общую ширину скроллбара:</p>
<pre class="brush: css; gutter: true; first-line: 1; highlight: []; html-script: false">::-webkit-scrollbar{
    width:12px;
}</pre>
<p>Теперь займёмся оформлением полосы прокрутки (светлосерый фон, серая граница, делаем границу чуть толще с левой стороны):</p>
<pre class="brush: css; gutter: true; first-line: 1; highlight: []; html-script: false">::-webkit-scrollbar-thumb{
    border-width:1px 1px 1px 2px;
    border-color: #777;
    background-color: #aaa;
}</pre>
<p>При наведении курсора (<code>:hover</code>) на полосу прокрутки делаем её более тёмной:</p>
<pre class="brush: css; gutter: true; first-line: 1; highlight: []; html-script: false">::-webkit-scrollbar-thumb:hover{
    border-width: 1px 1px 1px 2px;
    border-color: #555;
    background-color: #777;
}</pre>
<p>Ползунок в неактивном состоянии будет выглядеть как сплошной прямоугольник серого цвета (без границы)</p>
<pre class="brush: css; gutter: true; first-line: 1; highlight: []; html-script: false">::-webkit-scrollbar-track{
    border-width:0;
}</pre>
<p>При наведении курсора на ползунок, делаем его темнее и добавляем границу.</p>
<pre class="brush: css; gutter: true; first-line: 1; highlight: []; html-script: false">::-webkit-scrollbar-track:hover{
    border-left: solid 1px #aaa;
    background-color: #eee;
}</pre>
<p>Как видите, используя обычные CSS правила можно изменить скроллбар до неузнаваемости <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Успехов!</strong></p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/3d6GOtuUaIQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/css-oformlenie-skrollbara-v-stile-gmail.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Yii фреймворк: создание XML-RPC сервера</title>
		<link>http://www.simplecoding.org/yii-frejmvork-sozdanie-xml-rpc-servera.html</link>
		<comments>http://www.simplecoding.org/yii-frejmvork-sozdanie-xml-rpc-servera.html#comments</comments>
		<pubDate>Sat, 24 Dec 2011 20:15:06 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1247</guid>
		<description><![CDATA[На мой взгляд, XML-RPC протокол является одним из наиболее удобных способов передачи данных между Интернет-ресурсами. Можно, конечно, поспорить, но на изучение XML-RPC требуется минимальное количество времени, есть множество готовых библиотек, да и используется он очень широко. Поэтому я никогда не понимал, почему разработчики отличного фреймворка Yii решили не включать библиотеку для работы с XML-RPC в [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1021" class="wp-caption alignnone" style="width: 272px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/03/yii_xml_rpc.png" alt="yii xml rpc" title="yii xml rpc" width="262" height="189" style="float:left" class="size-full wp-image-1021" /><p class="wp-caption-text"> </p></div>
<p>На мой взгляд, <strong>XML-RPC протокол</strong> является одним из наиболее удобных способов передачи данных между Интернет-ресурсами. Можно, конечно, поспорить, но на изучение XML-RPC требуется минимальное количество времени, есть множество готовых библиотек, да и используется он очень широко. Поэтому я никогда не понимал, почему разработчики отличного <a href="http://www.yiiframework.com">фреймворка Yii</a> решили не включать библиотеку для работы с XML-RPC в дистрибутив. Хотя, возможно, это вопрос времени <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Тем не менее, работать нужно уже сейчас, и в этой статье мы разберём, как решить проблему с помощью сторонних библиотек.</p>
<p><em>Примечание</em>. Если вас интересует создание XML-RPC клиента, почитайте статью <a href="http://www.simplecoding.org/xml-rpc-i-yii-frejmvork.html">XML-RPC и Yii фреймворк</a>.</p>
<h2>Немного теории.</h2>
<p>Мы можем использовать два основных подхода при создании <strong>XML-RPC сервера</strong>.</p>
<p><strong>1) Отдельный скрипт.</strong> В этом случае создаём файл с именем вроде xmlrpc.php и помещаем его в корень сайта. В нём будет находиться код обработки XML-RPC запросов. Такой подход используется, например, в WordPress. Достоинство в том, что вам не нужно вносить никаких изменений в код вашего проекта, т.е. XML-RPC интерфейс получается независимым. С другой стороны, независимость приводит к тому, что вам будет гораздо сложнее работать со встроенными библиотеками фреймворка.</p>
<p><strong>2) Использование действий контроллера.</strong> Этот вариант гораздо интереснее. Во-первых, вы автоматически получаете доступ ко всем возможностям Yii. Во-вторых, в этом случае XML-RPC методы можно разделить по модулям. Т.е. подключение / отключение модуля будет автоматически подключать / отключать соответствующие XML-RPC методы.<br />
<span id="more-1247"></span><br />
Т.к. реализация первого подхода никакой сложности не представляет (фактически вы можете использовать примеры из документации к вашей библиотеке для работы с XML-RPC), мы рассмотрим второй вариант.</p>
<h2>Какие библиотеки можно использовать?</h2>
<p>По большому счёту – любые, т.к. подключение сторонних библиотек к Yii выполняется без особых проблем. Я обычно использую библиотеку <a href="http://scripts.incutio.com/xmlrpc/manual.php">Incutio XML-RPC Library</a>. Она достаточно простая, работает без проблем и, кроме того, используется в WordPress, а эта CMS используется очень часто.</p>
<p>Переходим к практике.</p>
<h2>Шаг 1. Подключаем библиотеку.</h2>
<p>Для этого скачиваем библиотеку и сохраняем файл <code>IXR_Library.php</code> в папку <code>protected/vendors</code>. Теперь подключить библиотеку можно так:</p>
<pre class="brush: php">Yii::import('application.vendors.*');
require_once ('IXR_Library.php');</pre>
<p>Этот код можно добавить в любое действие (<code>action</code>) контроллера.</p>
<h2>Шаг 2. Создаём точку входа.</h2>
<p>Как я уже говорил, в качестве точки входа мы используем действие контроллера. Код будет выглядеть примерно так:</p>
<pre class="brush: php">class MyController extends Controller {
	...
	public function actionXmlrpc() {
		Yii::import('application.vendors.*');
		require_once ('IXR_Library.php');

		$server = new IXR_Server(array(
			'my.hello' =&gt; array($this,'hello'),
		));
	}
	...
}</pre>
<p>В этом методе мы просто создаём объект типа <code>IXR_Server</code>, конструктору которого нужно передать массив с названиями XML-RPC методов. В данном случае в массиве только один элемент. Ключ этого элемента является названием XML-RPC метода, а значение – именем функции, которую нужно вызвать.</p>
<p><code>array($this,'hello')</code> означает, что будет вызван метод <code>hello</code> данного контроллера.</p>
<p>Тут нужно помнить об одном нюансе. Обычно в XML-RPC запросах не передаются данные сессий. Логин и пароль отправляются в каждом запросе в качестве параметров. Поэтому необходимо, обеспечить доступ к методу <code>actionXmlrpc()</code> без авторизации. Для этого немного изменим метод <code>accessRules</code></p>
<pre class="brush: php">public function accessRules() {
	return array(
		array('allow',  // allow all users to perform 'index' and 'view' actions
			'actions'=&gt;array('index','view','xmlrpc'),
			'users'=&gt;array('*'),
		),
		…,
	);
}</pre>
<h2>Шаг 3. Добавляем методы.</h2>
<p>Теоретически, можно ограничиться просто добавлением метода <code>hello</code>, который просто вернет «Hello, world!».</p>
<pre class="brush: php">public function hello($args) {
	return 'Hello, world!';
}</pre>
<p>Но в 99% нужно аутентифицировать пользователя. Добавим метод</p>
<pre class="brush: php">protected function xmlrpcLogin($username, $password) {
	$identity = new UserIdentity($username, $password);
	$identity-&gt;authenticate();
	if ($identity-&gt;errorCode === UserIdentity::ERROR_NONE) {
		Yii::app()-&gt;user-&gt;login($identity, 0);
		return true;
	}
	else {
		return false;
	}
}</pre>
<p>Здесь мы используем класс <code>UserIdentity</code>, который автоматически создаётся фреймворком Yii при создании приложения. В параметрах этого метода нужно передать логин и пароль. В случае успешной аутентификации метод вернёт TRUE, в противном случае – FALSE. Кроме того, данные пользователя будут доступны через Yii::app()-&gt;user, т.е. точно также как и при обычной работе с фреймворком.</p>
<p>Теперь перепишем код метода hello.</p>
<pre class="brush: php">public function hello($args) {
	if (!$this-&gt;xmlrpcLogin($args[0], $args[1])) {
		return new IXR_Error(-1, 'You did not provide the correct password');
	}
return 'Hello, world!';
}</pre>
<p>Здесь предполагается, что логин и пароль будут переданы в первом и втором параметрах XML-RPC запроса.</p>
<h2>Шаг 4. Проверяем работу.</h2>
<p>Для проверки достаточно создать обычный PHP скрипт со следующим кодом.</p>
<pre class="brush: php">require_once ('IXR_Library.php');

$client = new IXR_Client('http://my_site.domen/my/xmlrpc');
$client-&gt;debug = true;

$args = array();
$args[0] = 'login';
$args[1] = 'password';

if (!$client-&gt;query('my.hello', $args)) {
    die('Something went wrong - '.$client-&gt;getErrorCode().' : '.$client-&gt;getErrorMessage());
}
echo $client-&gt;getResponse();</pre>
<p>Как видите, создание XML-RPC сервера особой сложности не представляет. Конечно, самая сложная работа – это написание самих методов. Но не забывайте, что если у вас уже готов web интерфейс и логика по максимуму вынесена в модели, то вы сможете спокойно использовать её и в XML-RPC методах.</p>
<p><strong>Успехов!</strong></p>
<p><em>Полезная информация</em></p>
<p>Новогодний подарок от Inferno Solutions &#8211; всем новым клиентам панель ISP бесплатно и 30$ в подарок при заказе <a href="https://cp.inferno.name/cart.php">VPS в Германии</a>, Украине или Голландии! Укажите при заказе в примечании ISP+30.</p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/0gByRvLpcmc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-frejmvork-sozdanie-xml-rpc-servera.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Плагин для WordPress – Terms Descriptions (версия 1.2.0)</title>
		<link>http://www.simplecoding.org/plagin-dlya-wordpress-terms-descriptions-versiya-1-2-0.html</link>
		<comments>http://www.simplecoding.org/plagin-dlya-wordpress-terms-descriptions-versiya-1-2-0.html#comments</comments>
		<pubDate>Thu, 03 Nov 2011 19:55:24 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1233</guid>
		<description><![CDATA[Приветствую всех! На днях доделал очередную версию моего плагина для WordPress &#8211; Terms Descriptions. Скачать вы её можете на отсюда. Либо, если вы уже используете этот плагин, через систему обновлений WP. После выхода предыдущего релиза прошло довольно много времени и накопилось большое количество замечаний и предложений по его доработке. Сразу хочу сказать большое спасибо всем, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Приветствую всех!</strong></p>
<p>На днях доделал очередную версию моего плагина для <strong>WordPress</strong> &#8211; <strong>Terms Descriptions</strong>. Скачать вы её можете на <a href="http://wordpress.org/extend/plugins/terms-descriptions/">отсюда</a>. Либо, если вы уже используете этот плагин, через систему обновлений WP.</p>
<p><a href="http://wordpress.org/extend/plugins/terms-descriptions/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p>После выхода предыдущего релиза прошло довольно много времени и накопилось большое количество замечаний и предложений по его доработке. Сразу хочу сказать большое спасибо всем, кто помогал советами и идеями, присылал подробные отчеты об ошибках. Эта информация очень пригодилась!</p>
<p>В этой версии, конечно, реализованы не все пожелания и она не идеальна, но, надеюсь, что работать с ней будет удобнее, чем с предыдущими <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><em>Примечание</em>. Посмотреть описание предыдущих версий плагина можно в статье: <a href="http://www.simplecoding.org/plagin-wordpress-terms-descriptions">Плагин WordPress: Terms Descriptions</a>.</p>
<p>Рассмотрим по порядку все основные изменения.<br />
<span id="more-1233"></span></p>
<h2>Интерфейс</h2>
<p>Переделан практически полностью. Надеюсь, будет удобнее <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>В предыдущих версиях плагин создавал всего одну страницу в админке WP. На которой были расположены форма создания новых терминов, таблица с терминами и форма с настройками. Для первых версий плагина этого было достаточно. Но добавлять новые формы было сложно, т.к. страница получалась очень загроможденной.</p>
<p>Сейчас плагин создаёт три административных страницы, которые находятся в меню «Термины».</p>
<p>На первой странице (рис.1) размещена форма добавления новых терминов и таблица с уже существующими терминами.</p>
<p><a href="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_1.png"><img src="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_1-450x255.png" alt="terms_descriptions_1" title="terms_descriptions_1" width="450" height="255" class="size-medium wp-image-1235" /></a></p>
<p>Рис.1.</p>
<p>Принцип создания термина остался тем же, но форма изменилась. Во-первых, сейчас добавлена нормальная поддержка произвольных типов записей WP (custom post types). Во-вторых, для выбора записи (поста) используется поле с автокомплитом, а не выпадающий список с заголовками постов (рис. 2). Как оказалось, выпадающий список практически бесполезен, если блог содержит несколько сотен записей.</p>
<p><a href="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_2.png"><img src="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_2-450x90.png" alt="" title="terms_descriptions_2" width="450" height="90" class="alignnone size-medium wp-image-1236" /></a></p>
<p>Рис. 2.</p>
<p>Также добавлена пагинация (листалка) для таблицы с терминами и возможность обновления постоянных ссылок (об этом чуть ниже).</p>
<p>На второй странице находится форма со всеми основными настройками блога (рис. 3).</p>
<p><a href="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_3.png"><img src="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_3-450x235.png" alt="" title="terms_descriptions_3" width="450" height="235" class="alignnone size-medium wp-image-1237" /></a></p>
<p>Рис. 3.</p>
<p>На третьей странице (рис. 4) – инструменты для экспорта/импорта данных плагина и для пакетной загрузки терминов.</p>
<p><a href="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_4.png"><img src="http://www.simplecoding.org/wp-content/uploads/2011/11/terms_descriptions_4-450x335.png" alt="" title="terms_descriptions_4" width="450" height="335" class="alignnone size-medium wp-image-1238" /></a></p>
<p>Рис. 4.</p>
<h2>Хранение терминов</h2>
<p>Способ хранения и работы с терминами также был существенно переработан. Поэтому после обновления плагина в админке появится сообщение с кнопкой «Обновить БД». Я настоятельно рекомендую <strong>сделать резервную копию базы</strong> перед выполнением этой операции.</p>
<p>Причин для внесения этих изменений было две.</p>
<p>1) Оказалось, что часть пользователей создаёт большие списки терминов. И для работы с ними целесообразно создать отдельную таблицу.</p>
<p>2) Функция <code>get_permalink</code>, которая используется в WP для формирования ЧПУ, при определённых структурах ссылок оказывается довольно ресурсоемкой. Чтобы исключить её использование при формировании страниц блога, формирование ссылки теперь осуществляется один раз при создании термина. А для того, чтобы плагин правильно работал после изменения структуры URL, добавлена возможность пакетного обновления ссылок из админки. Кнопка «Обновить ссылки» находится справа над таблицей терминов (рис. 1). Т.е. если меняете структуру ЧПУ не забудьте обновить ссылки терминов.</p>
<h2>Парсеры</h2>
<p>Одними из самых неприятных проблем, с которыми я столкнулся при поддержке плагина, были конфликты с другими плагинами.</p>
<p>На сегодняшний день, существует множество плагинов и тем, которые изменяют содержимое постов. Предугадать все последствия таких изменений практически не реально. И хоть я и старался свести такие проблемы к минимуму, избежать их не получилось. Чем сложнее становился анализ текста, тем больше проблем возникало.</p>
<p>Например, количество багрепортов увеличилось в несколько раз после того как я добавил поддержку кавычек.</p>
<p>Повторения этой ситуации с новой версией я не хотел, поэтому принял решение добавить поддержку нескольких алгоритмов установки ссылок для терминов.</p>
<p>Сейчас в дистрибутиве плагина есть два парсера.</p>
<p><strong>1) Простой</strong>. Ставит ссылку на текст, который полностью совпадает с одним из терминов.</p>
<p><strong>2) Простой с поддержкой кавычек</strong>. Работает также как и простой, но дополнительно проверяет символы вокруг найденного термина, и, если они являются кавычками, преобразует термин в ссылку.</p>
<p>Переключение между парсерами осуществляется на странице Термины-&gt;Настройки (рис. 3).</p>
<h2>Пакетная загрузка терминов</h2>
<p>Позволяет загрузить сразу несколько терминов. Удобно, если у вас есть список терминов, сформированный с помощью какой-нибудь программы.</p>
<p>Форма пакетной загрузки находится на странице Термины -&gt; Инструменты.</p>
<p>Формат добавления терминов следующий. Каждый термин должен быть записан в отдельной строке. Можно указать несколько словоформ для терминов. Разделитель словоформ – символ <code>|</code>. Т.е. точно так же, как и при добавлении нового термина. Но есть важное отличие, в качестве последней словоформы нужно указать ссылку. Ссылкой может быть обычный URL (наличие <code>http://</code> обязательно) или <code>id</code> поста (пост нужно создать до добавления терминов).</p>
<p>Например, </p>
<p><code>яблоко|яблоки|яблок|яблочный|http://apples.com<br />
груша|груш|груши|24</code><br />
и т.д.<br />
здесь, 24 – id поста на который нужно поставить ссылку.</p>
<p><em>Хочу предупредить</em>. Добавление терминов занимает некоторое время. И, при попытке загрузить большой список, время выполнения скрипта может превысить лимит, установленный хостером. В таких случаях единственный вариант решения (если не считать вариант переезда на выделенный сервер) – загружать список по частям.</p>
<h2>Заключение</h2>
<p>В общем, надеюсь, новая версия вам понравится и позволит сделать работу более комфортной <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  И, конечно, жду ваших предложений, пожеланий и баг репортов <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Успехов!</strong></p>
<p>Полезные ссылки.</p>
<p><a href="http://cp.inferno.name/cart.php">Закажите VPS</a> Start и выше и получите 30$ + панель ISP в подарок! Отзывы &#8211; <a href="http://zapili.net">zapili.net</a></p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/KrclRDkRG3g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/plagin-dlya-wordpress-terms-descriptions-versiya-1-2-0.html/feed</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>WordPress: публикация постов с помощью XML-RPC с поддержкой таксономий</title>
		<link>http://www.simplecoding.org/wordpress-publikaciya-postov-s-pomoshhyu-xml-rpc-s-podderzhkoj-taksonomij.html</link>
		<comments>http://www.simplecoding.org/wordpress-publikaciya-postov-s-pomoshhyu-xml-rpc-s-podderzhkoj-taksonomij.html#comments</comments>
		<pubDate>Tue, 11 Oct 2011 08:02:30 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1229</guid>
		<description><![CDATA[WordPress на сегодняшний день является одой из самых популярных CMS и последнее время активно развивается. Но, к сожалению, это развитие не всегда получается гармоничным. Одной из возможностей, которая почему-то по возможностям постоянно отстаёт от остальной части движка, является XML-RPC. На сегодняшний день этот протокол является основным средством удалённой публикации постов. И, при этом, он фактически [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1230" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/10/wordpress-xml-rpc-publish.png" alt="wordpress xml-rpc publish" title="wordpress xml-rpc publish" width="300" height="239" class="size-full wp-image-1230" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>WordPress</strong> на сегодняшний день является одой из самых популярных CMS и последнее время активно развивается. Но, к сожалению, это развитие не всегда получается гармоничным.</p>
<p>Одной из возможностей, которая почему-то по возможностям постоянно отстаёт от остальной части движка, является <strong>XML-RPC</strong>. На сегодняшний день этот протокол является основным средством удалённой публикации постов. И, при этом, он фактически бесполезен если вы используете произвольные типы записей (custom post types) и таксономии (custom taxonomies). Ни один XML-RPC метод публикации постов в WP 3.2.1 их не поддерживает.</p>
<p>Конечно, можно надеятся, что в будущих версиях ситуация изменится в лучшую сторону, но ничто не мешает добавить нужные методы прямо сейчас.</p>
<p>Рассмотрим небольшой пример.<br />
<span id="more-1229"></span><br />
Допустим, нам нужно <strong>публиковать посты произвольного типа через XML-RPC и связывать их с таксономиями</strong>. При этом, таксономии могут быть как иерархическими, так и плоскими.</p>
<p><em>Примечание</em>. Подробнее о типах постов и таксономиях рассказано в статьях: <a href="http://www.simplecoding.org/wordpress-vyvod-zapisej-proizvolnyx-tipov-custom-post-types.html">WordPress: вывод записей произвольных типов (Custom Post Types)</a> и <a href="http://www.simplecoding.org/upravlenie-kontentom-v-wordpress-cms-situaciya-na-segodnya-i-blizhajshaya-perspektiva.html">Управление контентом в WordPress CMS: ситуация на сегодня и ближайшая перспектива</a>.</p>
<h2>Немного теории</h2>
<p>В WordPress предусмотрен фильтр (<code>xmlrpc_methods</code>), позволяющий добавлять новые методы во встроенный XML-RPC сервер. Делается это следующим образом:</p>
<pre class="brush: php">add_filter('xmlrpc_methods', 'add_xml_rpc_methods');</pre>
<p>Во втором параметре фильтра указываем имя функции, которая создаст запись в глобальном массиве XML-RPC методов.</p>
<pre class="brush: php">function add_xml_rpc_methods($methods) {
	$methods['my.my_method_name'] = 'my_method_name';
	return $methods;
}

function my_method_name($args) {
//обработка XML-RPC запроса и отправка ответа
}</pre>
<p>Чтобы создать XML-RPC метод нужно добавить новый элемент в массив <code>$methods</code>. Ключ этого элемента является именем метода, а значение – именем функции, которая выполняет обработку XML-RPC запроса и формирует ответ.</p>
<h2>Реализация: XML-RPC клиент</h2>
<p>Начнём с кода, который отправляет XML-RPC запрос. В данном случае будем использовать библиотеку <a href="http://scripts.incutio.com/xmlrpc/">The Incutio XML-RPC Library</a> (она же используется и в WordPress).</p>
<pre class="brush: php">require_once ('IXR_Library.php');

$client = new IXR_Client('http://my_blog.com/xmlrpc.php');
$client-&gt;timeout = 60000;

$requestData[0] = 0; //id блога
$requestData[1] = 'admin'; //имя пользователя
$requestData[2] = 'pass'; //пароль

$post = array();

$post['post_title'] = 'New Post';
$post['post_excerpt'] = 'Short description';
$post['post_content'] = 'This story about ...';
$post['post_status'] = 'draft';
$post['post_type'] = 'my_custom_post_type'; //тип поста
$post['post_date'] = date('Y-m-d H:i:s');
$post['post_modified'] = date('Y-m-d H:i:s');

//формируем массив с терминами таксономий
$terms = array();
$terms['taxonomy_1'][] = (int)$term['term_id_1'];
$terms['taxonomy_1'][] = (int)$term['term_id_2'];
$terms['taxonomy_2'][] = (int)$term['term_id_3'];
$terms['taxonomy_3'][] = (int)$term['term_id_4'];

$post['tax_input'] = $terms;

$requestData[3] = $post;

if (!$client-&gt;query('my.publish_post', $requestData)) {
	echo 'Publish Post error: '.$client-&gt;getErrorMessage();
	return;
}

$publishedPost = $client-&gt;getResponse();</pre>
<p>Прежде всего, создаём объект <code>IXR_Client</code>, конструктору которого передаём адрес скрипт, который выполняет обработку XML-RPC запросов (xmlrpc.php).</p>
<p>Затем формируем массив с данными для публикации поста. В первых трёх элементах указываем: <code>id</code> блога (на данный момент не используется), логин и пароль. В четвертом элементе – массив с данными нового поста.</p>
<p>Чтобы сократить количество кода на стороне XML-RPC сервера, названия полей этого массива должны совпадать с полями массива, который передаётся функции <a href="http://codex.wordpress.org/Function_Reference/wp_insert_post">wp_insert_post</a>. Кстати, большинство ключей элементов этого массива совпадает с именами полей таблицы posts базы данных.</p>
<p>Обратите внимание на параметр</p>
<pre class="brush: php">$post['post_type'] = 'my_custom_post_type'; //тип поста</pre>
<p>В нём указан тип поста, который мы хотим создать. Естественно, этот тип должен быть <a href="http://codex.wordpress.org/Function_Reference/register_post_type">заранее создан</a>.</p>
<p><strong>Отдельно остановимся на таксономиях.</strong></p>
<p>WordPress поддерживает таксономии 2-х типов: иерархические и плоские. Чтобы связать пост с терминами таксономий нужно перечислить их в элементе tax_input массива, который передаётся функции <code>wp_insert_post</code>. Например, так:</p>
<pre class="brush: php">'tax_input' =&gt; array('taxonomy_1' =&gt; array('term', 'term2', 'term3'), 'taxonomy_2' =&gt; array('term1', 'term2'))</pre>
<p>Здесь <code>taxonomy_1</code>, <code>taxonomy_2</code> – имена таксономий, а <code>term</code>, <code>term1</code> и т.д. – имена терминов.</p>
<p>Но здесь есть нюансы. Если публикуется «плоская» таксономия, то можно указать, либо имя термина, либо его <code>id</code>. При этом, <code>id</code> должен иметь тип <code>int</code>, если <code>id</code> сохранён в виде строки, то WordPress просто создаст новый термин. Для иерархических таксономий можно использовать только <code>id</code> термина (при этом нет ограничения на тип значения, оно будет автоматически приведено к типу <code>int</code>).</p>
<p>Т.е. универсальный вариант установки таксономий выглядит так:</p>
<pre class="brush: php">$terms['taxonomy_1'][] = (int)$term['term_id_1'];
$terms['taxonomy_1'][] = (int)$term['term_id_2'];
$terms['taxonomy_2'][] = (int)$term['term_id_3'];
$terms['taxonomy_3'][] = (int)$term['term_id_4'];</pre>
<p>Отправка запроса выполняется с помощью метода query, а прочитать результат можно используя <code>getResponse</code>.</p>
<h2>XML-RPC сервер</h2>
<p>На серверной стороне нужно зарегистрировать новый XML-RPC метод и написать функцию, которая будет обрабатывать запрос, и возвращать результат.</p>
<p><em>Примечание</em>. Следующий код можно добавить в плагин или в файл functions.php темы.</p>
<pre class="brush: php">add_filter('xmlrpc_methods', 'add_xml_rpc_methods' );

function add_xml_rpc_methods($methods) {
	$methods['my.publish_post'] = 'my_publish_post';
	return $methods;
}

function my_publish_post($args) {
	$blog_id = (int) $args[0];
	$username = $args[1];
	$password = $args[2];
	$post_data  = $args[3];

	if ( !get_option( 'enable_xmlrpc' ) ) {
		return new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
	}

	$user = wp_authenticate($username, $password);

	if (is_wp_error($user)) {
		return new IXR_Error(403, __('Bad login/pass combination.'));
	}

	wp_set_current_user( $user-&gt;ID );

	if ( !current_user_can( 'edit_private_posts' ) ) {
		return new IXR_Error( 401, __( 'Sorry, you cannot edit private posts.' ) );
	}

	if (!is_array($post_data)) {
		return new IXR_Error( 401, __( 'Sorry, no post data not found.' ) );
	}

	$id = wp_insert_post( $post_data );

	if ($id === 0) {
		return new IXR_Error( 401, __( 'Post save error.' ) );
	}

	$post = array();
	$post['id'] = $id;
	$post['permalink'] = get_permalink($id);

	return $post;
}</pre>
<p>Здесь мы регистрируем XML-RPC метод <code>my.publish_post</code> и указываем, что при обращении к нему WordPress должен вызвать функцию <code>my_publish_post</code>.</p>
<p>Большая часть кода в этой функции совпадает с большинством обработчиков стандартных XML-RPC методов WP. Собственно он оттуда и скопирован <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  . Этот код проверяет, разрешен ли XML-RPC для данного блога (строки 14-16, кстати, не забудьте его включить в админке на странице Settings -&gt; Writing), аутентифицирует пользователя и проверяет, достаточно ли у него прав для публикации поста.</p>
<p>Сама публикация выполняется с помощью всего одной функции <code>wp_insert_post</code> (строка 34).</p>
<p>Клиенту возвращаем <code>id</code> созданного поста и постоянную ссылку на него (формируем с помощью функции get_permalink).</p>
<h2>Заключение</h2>
<p>Как видите, принцип достаточно простой. Любую встроенную функцию WP можно вызвать через XML-RPC протокол и использовать все возможности движка при удалённой публикации постов.</p>
<p>Если есть вопросы или замечания, пишите, постараюсь ответить.</p>
<p><strong>Успехов!</strong></p>
<p>Интересные ссылки</p>
<p>Закажите <a href="http://printfotobook.ru">печать фотокниг</a> тремя способами: онлайн, в офисе или вип</p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/7FlRb0jVn4Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/wordpress-publikaciya-postov-s-pomoshhyu-xml-rpc-s-podderzhkoj-taksonomij.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>jQuery: обработка параметров URL</title>
		<link>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html</link>
		<comments>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html#comments</comments>
		<pubDate>Fri, 19 Aug 2011 07:45:55 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1225</guid>
		<description><![CDATA[Приветствую всех! Сегодня хочу показать небольшой пример использования библиотеки jQuery для работы с параметрами ссылок. Предположим на нашей странице есть ссылка, клик по которой отправляет запрос на выполнение некоторой операции. Пускай это будет удаление какого-нибудь объекта. HTML разметка такой ссылки может выглядеть следующим образом. &#60;a class="delete" href="http://www.simplecoding.org/script.php?action=delete_object&#38;object_id=1"&#62;Удалить&#60;/a&#62; Как видите, ссылка содержит два параметра (action и [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1226" class="wp-caption alignnone" style="width: 299px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/08/jquery_parsequery.png" alt="jquery parsequery" title="jquery parsequery" width="289" height="152" class="size-full wp-image-1226" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>Сегодня хочу показать небольшой пример использования библиотеки <strong>jQuery</strong> для работы с параметрами ссылок.</p>
<p>Предположим на нашей странице есть ссылка, клик по которой отправляет запрос на выполнение некоторой операции. Пускай это будет удаление какого-нибудь объекта.</p>
<p><strong>HTML разметка</strong> такой ссылки может выглядеть следующим образом.</p>
<pre class="brush: html">&lt;a class="delete" href="http://www.simplecoding.org/script.php?action=delete_object&amp;object_id=1"&gt;Удалить&lt;/a&gt;</pre>
<p>Как видите, ссылка содержит два параметра (<code>action</code> и <code>object_id</code>), значения которых PHP скрипт сможет получить из массива <code>$_GET</code>.</p>
<p>Теперь, мы хотим выполнить удаление объекта с помощью <strong>AJAX запроса</strong>. Изменять ради него ссылку нет никакой необходимости. Просто назначаем обработчик для события <code>click</code>.<br />
<span id="more-1225"></span></p>
<pre class="brush: javascript">$('a.delete').click(function() {
  return false;
});</pre>
<p>Этот код блокирует отправку обычного запроса при клике по ссылке. Нам нужно <strong>получить параметры и отправить AJAX запрос</strong>.</p>
<p>В обработчике события <strong>click</strong> получить значение атрибута <strong>href</strong> ссылки можно следующим образом.</p>
<pre class="brush: javascript">$(this).attr('href')</pre>
<p>Затем нужно найти в этой строке параметры. Тут есть <strong>два варианта</strong>.</p>
<p>1) Если вам достаточно параметров, указанных в атрибуте <strong>href</strong> и вы не хотите их изменять, то просто передать методам <code>$.ajax</code> (или <code>$.post</code>, или <code>$.get</code>) строку с параметрами запроса.</p>
<p>Т.е. код будет выглядеть примерно так</p>
<pre class="brush: javascript">var params = $(this).attr('href').split('?');
$.post('ajax_delete.php', params[1], function(response) {
    console.log(response);
} );</pre>
<p>Здесь мы с помощью метода <code>split</code> разбили запрос на две части (по знаку вопроса), и передали методу <code>$.post</code> второй элемент массива <code>params</code>. Для данного примера он выглядит так<br />
<code>action=delete_object&amp;object_id=1</code></p>
<p>2) Если перед отправкой AJAX запроса нужно изменить/удалить/добавить какие-то параметры, то удобнее всего преобразовать строку с параметрами в хеш.</p>
<p>Для этих целей существует специальный плагин – <a href="http://plugins.jquery.com/project/parseQuery">parseQuery</a></p>
<p>Использовать его можно так.</p>
<pre class="brush: javascript">var params = $.parseQuery($( this ).attr( 'href' ).split('?'));</pre>
<p>В результате вы получите хеш</p>
<pre class="brush: javascript">{
	action: delete_object,
	object_id: 1
}</pre>
<p>Код отправки AJAX запроса при этом не изменяется. Точно также передаёте переменную <code>params</code> во втором параметре метода <code>$.post</code>.</p>
<p>В заключение посмотрите код обработчика целиком.</p>
<pre class="brush: javascript">$(document).ready(function() {
	$('a.delete').click( function() {
		var params = $(this).attr('href').split('?');
		$.post('ajax_delete.php', params[1], function(response) {
			console.log(response);
		});
		return false;
	});
});</pre>
<p>Как видите, задача решается с помощью минимального количества кода. И если у посетителя будет отключен JavaScript, то ничего особенного не произойдет. При кликах по ссылкам будут отправляться обычные запросы.</p>
<p>Если есть вопросы или замечания, пишите.</p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать</em></p>
<p>Платежный модуль <a href="http://www.rugento.ru/robokassa-payment-module.html" target="_blank">Robokassa для Magento</a> с поддержкой.</p>
<p>Нужна фотокнига? В наличие <a href="http://printfotobook.ru/primery_fotoknig">фотокниги образцы</a>, множество видов дизайна и верстки</p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/C8TaO4i7wF0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>HTML5: загрузка файлов с помощью Drag &amp; Drop</title>
		<link>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html</link>
		<comments>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html#comments</comments>
		<pubDate>Thu, 21 Jul 2011 13:13:41 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1222</guid>
		<description><![CDATA[Приветствую всех! В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно. Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1223" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/07/html5_drag_drop_upload.png" alt="html5 drag&amp;drop upload" title="html5 drag&amp;drop upload" width="300" height="186" class="size-full wp-image-1223" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно.</p>
<p>Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку файлов на сервер. В большинстве случаев вам предложат стандартное поле с кнопкой выбора файла с вашего компьютера и/или поле, в котором можно указать URL файла, размещенного где-нибудь в Сети.</p>
<p>Загрузку файлов с локального компьютера трогать пока не будем, я планирую опубликовать отдельный пост на эту тему, разберем загрузку с удалённого сервера.</p>
<p>Проблемы начинаются с первого же шага. Даже если вы четко понимаете, где искать URL и хорошо умеете пользоваться инструментами вроде <strong>firebug</strong>, то всё равно потребуется несколько кликов мышкой чтобы получить нужный адрес. Было бы гораздо удобнее просто перетянуть нужную картинку из одного окна браузера в другое.<br />
<span id="more-1222"></span><br />
Пример реализации такого интерфейса я покажу в этой статье. Если хотите, можете посмотреть, как он работает на демонстрационной страничке или скачать архив с исходниками.</p>
<p><a href="http://demosites.simplecoding.org/images-upload/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a><a href='http://www.simplecoding.org/wp-content/uploads/2011/07/images-upload.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><strong>Обратите внимание!</strong> Данный пример работает только в браузере <strong>Google Chrome</strong>. По-идее, поддержка всех необходимых технологий есть в <strong>Firefox</strong> и <strong>Safari</strong>, но с ними я пока не разбирался.<br />
В качестве объектов для «перетягивания» я брал в основном картинки с википедии. Было замечено несколько проблем связанных с не латинскими символами в URL картинок, но чтобы не перегружать пример проверками и преобразованиями я их оставил как есть.</p>
<h2>Принцип работы</h2>
<p>Стандарт HTML5 предусматривает поддержку «перетягивания» объектов страницы (Drag and Drop). Кстати, пример простейшей реализации D&#038;D я уже показывал – <a href="http://www.simplecoding.org/drag-drop-s-ispolzovaniem-html5.html">Drag &#038; Drop с использованием HTML5</a>. И, кроме того, есть довольно много JavaScript библиотек, реализующих поддержку D&#038;D.</p>
<p>Но тут важно понимать, что если необходимо «перетягивать» картинки со сторонних ресурсов, то использовать библиотеки не получится. Т.к. вы не сможете добавить свой JS код на чужую страницу. А для того, чтобы загрузить картинку, нам нужно получить её URL, т.е. браузер должен вместе с перетягиваемым объектом передавать и его параметры (например, атрибут src картинки или весь тег img).</p>
<p>В этом случае мы можем создать на своей странице «приёмник» картинок. Это будет обычный <code>div</code> которому назначен обработчик события <code>drop</code>. Если пользователь «сбросит» картинку над этим div&#039;ом, то будет вызван обработчик и в первом параметре он получит объект, содержащий информацию о перетягиваемой картинке.</p>
<p>Дальше всё достаточно просто. Если мы получили нужный URL, то можно отправить AJAX-запрос серверному скрипту, который выполнит загрузку файла.</p>
<h2>Реализация</h2>
<p>Начнём со страницы нашего приложения.</p>
<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
        &lt;title&gt;Images Upload&lt;/title&gt;
		&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;
    &lt;/head&gt;
    &lt;body&gt;
		&lt;div id="images"&gt;&lt;/div&gt;
		&lt;div id="img_target"&gt;&lt;/div&gt;
		&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"&gt;&lt;/script&gt;
		&lt;script src="main.js"&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>На ней размещены два блока: <code>images</code> – здесь будем показывать загруженные изображения и <code>img_target</code> – на этот блок нужно перетягивать картинки.</p>
<p>Внизу страницы подключаем библиотеку jQuery и скрипт main.js, который будет отправлять информацию о перетянутых изображениях на сервер.</p>
<p><strong>Рассмотрим main.js</strong></p>
<pre class="brush: javascript">$(function() {
    $('#img_target')
        .bind('dragenter', function(event) {
            $(this).addClass('drop_here');
            return false;
        })
        .bind('dragleave', function(event) {
            $(this).removeClass('drop_here');
            return false;
        })
        .bind('dragover', function(event) {
            return false;
        })
        .bind('drop', function(event) {
            $(this).removeClass('drop_here');
			var srcRegex = /src=\"([^\s]+)\"/ig;
            var data = event.originalEvent.dataTransfer.getData('text/html');
			var img_data = srcRegex.exec(data);
			$.post('upload.php', {'file_url':img_data[1]}, function(res) {
				var response = eval('(' + res + ')');
				$('#images').append($('&lt;img src="' + response.file_url + '" /&gt;'));
			});
            return true;
        });
});</pre>
<p>Здесь мы назначаем обработчики событиям <code>dragenter</code>, <code>dragleave</code> и <code>dragover</code>. Все они должны просто возвращать false и, чтобы как-то проинформировать пользователя о том, что можно «сбрасывать» картинку, в обработчике <code>dragenter</code> устанавливаем CSS класс <code>drop_here</code> для блока-приёмника.</p>
<p>Основная часть работы выполняется в обработчике события <code>drop</code>. При возникновении этого события мы читаем информацию о «сброшенном» объекте и «вырезаем» значение атрибута <code>src</code>, т.е. URL картинки (строки 16-18). Информация передается в объекте event.originalEvent.dataTransfer (строка 17).</p>
<p>Затем <strong>формируем обычный AJAX запрос</strong> и в качестве параметра передаём ему найденный URL.</p>
<p>Серверный скрипт (upload.php) получит URL изображения на удалённом сервере и загрузит его. А в ответе на AJAX запрос он отправит новый URL загруженной картинки.</p>
<p>В свою очередь, обработчик AJAX-запроса создаст тег <code>img</code> и вставит его в блок <code>images</code>. Таким образом, загруженные картинки будут появляться над полем загрузки.</p>
<p><strong>Рассмотрим upload.php</strong></p>
<pre class="brush: php">&lt;?php

define('BASE_URL', 'http://localhost/tests/images-upload/');

function upload_from_url($file_url) {
	$url_segments = explode('/', $file_url);
	$file_name = urldecode(end($url_segments));
	if (false !== $file_name) {
		$file_name_parts = explode('.', $file_name);
		if (in_array(strtolower(end($file_name_parts)), array('jpeg','jpg','png','gif'))) {
			$destination=fopen("upload/".$file_name,"w");
			$source=fopen($file_url,"r");
			$maxsize=300*1024;
			$length=0;
			while (($a=fread($source,1024))&#038;&#038;($length&lt;$maxsize)) {
				$length=$length+1024;
				fwrite($destination,$a);
			}
			fclose($source);
			fclose($destination);
		}
	}
	$new_file_url = BASE_URL.'upload/'.$file_name;
	return $new_file_url;
}

$res = array('err' =&gt; 'Не указан URL файла');

if (isset($_POST['file_url'])) {
	$new_url = upload_from_url($_POST['file_url']);
	$res = array('file_url' =&gt; $new_url);
}

echo json_encode($res);</pre>
<p>Принцип работы следующий. Читаем URL картинки и пытаемся её загрузить (строки 29-32).</p>
<p>Если картинка загружена, сохраняем её в папку <code>upload</code>. Получение картинки с удалённого сервера осуществляется с помощью функций <code>fread</code>. Файл читаем блоками по 1кБ (строки 15-18). Такой подход позволяет прервать загрузку файла, если его размер превышает заданный предел (в данном случае 300кБ).</p>
<p>После загрузки файла формируем для него URL и отправляем браузеру в формате <strong>JSON</strong>.</p>
<p>Как видите, реализовать такой загрузчик несложно. И пользоваться им достаточно удобно. Естественно, основным недостатком является поддержка HTML5 браузерами, точнее её отсутствие <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Тем не менее, если вы создаёте интерфейс для сотрудников какой-нибудь компании, и можете оговорить тип браузера, то HTML5 вполне можно использовать.</p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать.</em></p>
<p>Фотокнига — фантастический <a href="http://imagebook.ru/sjurpriz_ljubimomu_muzhchine">сюрприз для любимого мужчины</a>. Попробуйте сами!</p>
<p>Правильно подготовим <a href="http://online-nalogi.ru/3_ndfl_pokupka_kvartiry">3-ндфл при покупке квартиры за 2011 год</a>, дадим инструкции для получения вычета</p>
<p>Нужно распарсить сайт? Интересный пример как написан <a href="http://www.sergunik.name/?p=140" title="php parser">парсер на php</a>. Можно даже скачать скрипт парсера.</p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/_PxOUsLX348" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Как показать на Google Maps объекты, находящиеся в заданной области</title>
		<link>http://www.simplecoding.org/kak-pokazat-na-google-maps-obekty-naxodyashhiesya-v-zadannoj-oblasti.html</link>
		<comments>http://www.simplecoding.org/kak-pokazat-na-google-maps-obekty-naxodyashhiesya-v-zadannoj-oblasti.html#comments</comments>
		<pubDate>Tue, 28 Jun 2011 09:48:03 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1214</guid>
		<description><![CDATA[Показать пример решения такой задачи меня попросили в комментариях к одной из предыдущих статей о Google Maps. С выполнением этой просьбы я довольно сильно затянул, но, надеюсь, эта статья кому-нибудь пригодится Начнём с постановки задачи Предположим, у нас есть данные о группе объектов (их названия и координаты). Необходимо отметить их на карте с помощью маркеров. [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1215" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/06/google_maps.png" alt="google maps" title="google maps" width="300" height="197" style="float:left" class="size-full wp-image-1215" /><p class="wp-caption-text"> </p></div>
<p>Показать пример решения такой задачи меня попросили в комментариях к одной из предыдущих статей о <strong>Google Maps</strong>. С выполнением этой просьбы я довольно сильно затянул, но, надеюсь, эта статья кому-нибудь пригодится <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Начнём с постановки задачи</strong></p>
<p>Предположим, у нас есть данные о группе объектов (их названия и координаты). Необходимо отметить их на карте с помощью маркеров. При этом, показать нужно не все объекты, а только те, которые находятся внутри заданной области.</p>
<p>Будем считать, что заданная область представляет собой окружность, т.е. мы знаем координаты её центра и радиус. А координаты объектов находятся в KML файле (это XML формат, разработанный для описания объектов на Google maps).<br />
<span id="more-1214"></span><br />
Таким образом, <strong>алгоритм расстановки объектов</strong> получается довольно простым.</p>
<p>1) Читаем координаты объекта из KML файла.<br />
2) Рассчитываем расстоянием между центром окружности и текущим объектом.<br />
3) Если это расстояние меньше радиуса окружности, ставим маркер, если больше – пропускаем объект.</p>
<p>Переходим к решению.</p>
<p>Посмотреть, как работает этот пример, можно на демонстрационной страничке или установив скрипты на своем сервере.</p>
<p><a href="http://demosites.simplecoding.org/google-maps/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a> <a href='http://www.simplecoding.org/wp-content/uploads/2011/06/google_maps.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<h2>Серверная часть</h2>
<p>Начнем с серверного скрипта, который формирует страницу с картой (index.php).</p>
<pre class="brush: php">&lt;?php
$organizations = simplexml_load_file('doc.kml');

$organizations_data = array();

foreach ($organizations-&gt;Folder-&gt;Placemark as $organisation) {
    $organizations_data[] = array(
        'name' =&gt; (string)$organisation-&gt;name,
        'coordinates' =&gt; (string)$organisation-&gt;Point-&gt;coordinates,
    );
}
?&gt;

&lt;!DOCTYPE html&gt;

&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;title&gt;Объекты на Google Maps&lt;/title&gt;
    &lt;script&gt;
&lt;?php
    echo 'var organizations = '.json_encode($organizations_data).';';
?&gt;
    &lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;h1&gt;Google Maps: отображение объектов, которые находятся в заданной области&lt;/h1&gt;

&lt;div id="my_map" style="width:600px;height:400px"&gt;&lt;/div&gt;

&lt;script src="main.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Прежде всего, загружаем данные из KML файла (строка 2). Т.к. это обычный XML файл, то мы можем использовать любую библиотеку для работы с этим форматом. В данном случае – <a href="http://php.net/manual/en/book.simplexml.php">SimpleXML</a>.</p>
<p>Затем, необходимо обеспечить доступ к этим данным на клиентской стороне, т.к. настройка Google Maps выполняется с помощью <strong>JavaScript</strong>.</p>
<p>Для этого мы формируем массив с необходимыми данными (строки 6-11), преобразовываем его в <strong>JSON</strong> формат (строка 22) и присваиваем переменной <code>organizations</code> (строка 22) в теге <code>script</code>. Таким образом, мы получаем <strong>JavaScript массив</strong> с координатами всех объектов из KML файла.</p>
<p>Тут я хочу сделать небольшое отступление. В принципе, работать с KML файлом можно и на стороне браузера, это несложно. Но в общем случае, этот файл не обязательно будет находиться на вашем сервере, а кросс-доменные (XSS) запросы запрещены политикой безопасности браузеров. Т.е. придётся искать какой-нибудь обходной путь. Подробнее на эту тему можно почитать <a href="http://www.simplecoding.org/kak-obojti-zapret-na-xss.html">здесь</a>, <a href="http://www.simplecoding.org/xss-i-same-origin-policy.html">здесь</a>, <a href="http://www.simplecoding.org/xss-s-ispolzovaniem-jsonp-i-jquery.html">здесь</a> и <a href="http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html">здесь</a>.</p>
<p>Подробно разбирать работу с <strong>SimpleXML</strong>, думаю, смысла не имеет. Для данного примера достаточно понимать, что после загрузки файла вы получите объект, имеющий такую же структуру как и xml-документ.</p>
<p>Т.е. вызов <code>$organizations-&gt;Folder-&gt;Placemark</code> вернет вам содержимое тега <code>&lt;Placemark&gt;</code> в документе с такой структурой</p>
<pre class="brush: xml">&lt;kml xmlns="…" xmlns:kml="…" xmlns:atom="…"&gt;
&lt;Folder&gt;
	&lt;Placemark&gt;
	…
	&lt;/Placemark&gt;
&lt;/Folder&gt;
&lt;/kml&gt;</pre>
<p><em>Обратите внимание!</em> Библиотека чувствительна к регистру тегов в xml-файле.</p>
<p>На самой странице мы создаём блок для карты (<code>my_map</code>).</p>
<p>И подключаем файл main.js, который и будет выполнять настройку карты.</p>
<h2>Клиентская часть</h2>
<p>Сразу посмотрим на весь скрипт целиком.</p>
<pre class="brush: javascript">var map, circle, circleOptions, setCenter, marker, organizations_markers;

function initialize() {
    var centerPoint = new google.maps.LatLng(48.67, 44.47); //Волгоград
    var myOptions = {
        zoom: 12,
        center: centerPoint,
        mapTypeId: google.maps.MapTypeId.HYBRID
    }
    map = new google.maps.Map(document.getElementById("my_map"), myOptions);

    //радиус окружности - 5 км
    var radius = 5;

    circleOptions = {
        center: centerPoint,
        fillColor: "#00AAFF",
        fillOpacity: 0.5,
        strokeColor: "#FFAA00",
        strokeOpacity: 0.8,
        strokeWeight: 2,
        clickable: false,
        radius: radius*1000
    }

    //рисуем окружность
    circle = new google.maps.Circle(circleOptions);
    circle.setMap(map);

    //устанавливаем маркеры организаций
    organizations_markers = [];
    for (var i = 0; i &lt; organizations.length; i++) {
        var ll = organizations[i].coordinates.split(',');
        var latlng = new google.maps.LatLng(ll[1], ll[0]);
        if (distHaversine(latlng, centerPoint) &lt; radius) {
            organizations_markers[i] = new google.maps.Marker({
                    position:latlng,
                    clickable:true
                });
            organizations_markers[i].setMap(map);
        }
    }
}

function loadScript() {
    var script = document.createElement("script");
    script.src = "http://maps.google.com/maps/api/js?sensor=false&#038;callback=initialize";
    document.body.appendChild(script);
}

rad = function(x) {return x*Math.PI/180;}

//эта функция используются для определения расстояния между точками на
//поверхности Земли, заданных с помощью географических координат
//результат возвращается в км
distHaversine = function(p1, p2) {
    var R = 6371; // earth's mean radius in km
    var dLat  = rad(p2.lat() - p1.lat());
    var dLong = rad(p2.lng() - p1.lng());

    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;

    return d.toFixed(3);
}

window.onload = loadScript;</pre>
<p>В первую очередь мы создаём карту и устанавливаем её основные параметры (координаты центра, приближение). Для этого, назначаем обработчик событию <code>window.onload</code> (строка 69). Этот обработчик добавляет на страницу тег <code>script</code> в параметре <code>src</code> которого передается адрес имя метода, который будет вызван после загрузки Google Maps (в данном случае &#8211; <code>initialize</code>). Таким образом, все наши настройки выполняются в этом методе.</p>
<p>Выполняем установку параметров карты (строки 4-10). Мы указали: центральную точку (<code>centerPoint</code>), приближение (<code>zoom</code>) и тип карты (<code>mapTypeId</code>).</p>
<p>Теперь рисуем окружность (строки 13-28). Её центр совпадает с центром карты, а радиус равен 5 км. В настройках окружности указываем толщину и цвет линии, цвет и прозрачность фона и другие параметры.</p>
<p>После этого <strong>расставляем маркеры объектов</strong>.</p>
<p>Напомню, что координаты этих объектов находятся в массиве organizations, который был сформирован серверным скриптом.</p>
<p>Т.е. нам нужно пройтись по всем элементам этого массива и рассчитать расстояние от центра окружности до текущего объекта (строки 31-42).</p>
<p>Расчет расстояний для точек на поверхности Земли выполняется с помощью функции гаверсинусов (<code>distHaversine</code>). Её реализацию на JavaScript я взял <a href="http://stackoverflow.com/questions/1502590/calculate-distance-between-two-points-in-google-maps-v3">здесь</a>.</p>
<p>Если это расстояние меньше заданного, создаём маркер и показываем его на карте (строки 36-40). В противном случае – переходим к следующему объекту.</p>
<p>Как видите, алгоритм достаточно простой. Если немного усовершенствовать скрипт, можно сделать окружность перемещаемой и с переменным радиусом. Таким образом, имея хорошую базу объектов для какого-нибудь города, можно получить довольно удобный инструмент определения ближайших к заданной точке объектов.</p>
<p>Если есть вопросы или замечания, пишите, постараюсь ответить в комментариях <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать</em></p>
<p>Хотите создать свой сайт? <a href="http://template-cms.ru/">Template CMS &#8211; быстрая и маленькая CMS!</a> Поможет решить эту задачу с минимальными затратами времени и ресурсов.</p>
<p>В раздумьях, <a href="http://imagebook.ru/podarok_k_svadbe">что подарить на свадьбу друзьям</a>? Попробуйте свадебную фотокнигу.</p>
<p>Заполним <a href="http://online-nalogi.ru"> 3-ндфл за 2011</a> год за 1 день, от 500 рублей!</p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/I_MnhAf6vGk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/kak-pokazat-na-google-maps-obekty-naxodyashhiesya-v-zadannoj-oblasti.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>JavaScript XSS: получение данных от facebook и вконтакте</title>
		<link>http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html</link>
		<comments>http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html#comments</comments>
		<pubDate>Sun, 22 May 2011 11:02:21 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1211</guid>
		<description><![CDATA[О виджетах популярных социальных сетей знают практически все web мастера. Использовать их достаточно просто. В большинстве случаев нужно вставить блок с JavaScript кодом в шаблон страницы. Но что мы получаем в результате? Стандартную кнопку, позволяющую посетителю быстро опубликовать ссылку на текущую страницу в социальной сети и обычно счетчик таких публикаций. При этом, внешний вид такого [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1212" class="wp-caption alignnone" style="width: 221px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/05/facebook_vkontakte.png" alt="facebook vkontakte" title="facebook vkontakte" width="211" height="141" class="size-full wp-image-1212" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>О <strong>виджетах популярных социальных сетей</strong> знают практически все web мастера. Использовать их достаточно просто. В большинстве случаев нужно вставить блок с <strong>JavaScript</strong> кодом в шаблон страницы.</p>
<p>Но что мы получаем в результате? Стандартную кнопку, позволяющую посетителю быстро опубликовать ссылку на текущую страницу в социальной сети и обычно счетчик таких публикаций.</p>
<p>При этом, внешний вид такого виджета полностью определяется разработчиком и изменить его довольно проблематично, т.к. он находится внутри <code>iframe</code>, который загружен с другого домена. То есть ваши стили не будут применяться к этому iframe&#039;у.</p>
<p>Безусловно, такие виджеты выглядят очень не плохо и, самое главное, они узнаваемы. Большинство посетителей прекрасно понимает как ими пользоваться безо всяких дополнительных подсказок.</p>
<p>Тем не менее, бывают ситуации когда нужно изменить внешний вид виджета, да и грузить JavaScript код социальных сетей не очень хочется.</p>
<p>В этом случае придется <strong>создать свой виджет</strong> и обеспечить правильную его работу с социальными сетями.</p>
<p>Именно о таком решении я хочу рассказать в этой статье. В качестве примера возьмем <strong>facebook</strong> и <strong>вконтакте</strong>. Выбор этот сделан не случайно, разница между API этих сервисов довольно ощутимая. Чуть ниже вы поймете почему.<br />
<span id="more-1211"></span><br />
Условно, виджет можно разбить на две части.</p>
<p>1) Кнопка публикации.<br />
2) Счетчик публикаций.</p>
<p>Рассмотрим их подробнее.</p>
<h2>Кнопка публикаций</h2>
<p>Здесь все предельно просто. В обоих случаях информация передаётся в параметрах GET запроса. Т.е. достаточно сформировать ссылки следующего вида.</p>
<p>Для facebook:</p>
<pre class="brush: html">&lt;a href="http://www.facebook.com/sharer.php?u=url&#038;t=text" target="_blank"&gt;facebook&lt;/a&gt;</pre>
<p>Для вконтакте:</p>
<pre class="brush: html">&lt;a href="http://vkontakte.ru/share.php?url=url" target="_blank"&gt;вконтакте&lt;/a&gt;';</pre>
<p>Вместо <code>url</code> и <code>text</code> нужно подставить адрес и описание страницы, соответственно.</p>
<h2>Счетчик публикаций</h2>
<p>Здесь код будет немного сложнее. В обоих случаях для получения значений счетчика нужно отправить запрос серверу социальной сети. И тут начинаются варианты.</p>
<p>В большинстве источников, которые я видел в Сети, предлагают отправлять такой запрос со своего сервера (с помощью PHP) и затем кэшировать результат. Мне этот подход не нравится по нескольким причинам.</p>
<p>1) Любой запрос занимает какое-то время, которое прибавляется к общему времени формирования страницы. Кэширование в какой-то степени решает эту проблему (запросы будут отправляться не при каждом просмотре страницы), но не полностью.</p>
<p>2) При большом количестве запросов, социальная сеть может заблокировать ваш IP (зависит от политики социальной сети).</p>
<p>3) Создаётся дополнительная нагрузка на ваш сервер.</p>
<p>Второй вариант – <strong>отправлять запросы со стороны клиента, с помощью JavaScript</strong>.</p>
<p>В этом случае запрос уйдет из браузера посетителя и, по крайней мере, IP адреса таких запросов будут отличаться. Кроме того, запрос можно отправить после полной загрузки страницы и работа вашего сайта ни коим образом не будет зависеть от доступности социальной сети.</p>
<p>Но, при реализации такого подхода, возникают две <strong>проблемы</strong>.</p>
<p><strong>1) Встроенная защита браузеров от кросс-доменных запросов.</strong></p>
<p>Т.е. вы не можете отправить AJAX запрос на другой домен, но можно вставить в страницу тег <code>script</code> и в его атрибуте <code>src</code> указать адрес нужного скрипта на другом домене. В результате браузер загрузит нужный вам скрипт и выполнит код, находящийся в нём.</p>
<p>При использовании jQuery задача решается с минимумом усилий. Например, так:</p>
<pre class="brush: javascript">$.getJSON('http://vkontakte.ru/share.php?act=count&#038;index=1&#038;url=page_url&#038;callback=?', function(response) {
	…
});</pre>
<p>Обратите внимание на параметр <code>callback=?</code>. Если он указан, то jQuery вставит тег <code>script</code> внутрь страницы. Вообще параметр <code>callback</code> разработан для поддержки <strong>JSONP</strong> и указывает серверу, что ответ в JSON формате нужно передать в качестве параметра указанной функции. Имя этой функции jQuery формирует автоматически и подставляет вместо знака вопроса.</p>
<p>Естественно, JSONP должен поддерживаться на стороне сервера. И сейчас мы разберем какие ответы мы получим от социальных сетей на практике.</p>
<p><strong>2) Формат ответа социальной сети.</strong></p>
<p>С facebook всё отлично. Эта социальная сеть поддерживает JSONP и если мы отправим запрос вида.</p>
<pre class="brush: javascript">$.getJSON('http://graph.facebook.com/' + encodeURI(page_url)
		+ '&#038;callback=?', function(response) {
	if (response.shares !== undefined) {
		fb_counter = response.shares;
	}
	$('#facebook_count').html(response.shares);
});
<pre>

То получим следующий ответ.
<pre class="brush: javascript">jQuery16105957901661749929_1306057803097({
   "id": "http://www.smashingmagazine.com/",
   "shares": 5454
});</pre>
<p><code>jQuery16105957901661749929_1306057803097</code> – имя функции, которое сгенерировала jQuery.<br />
В первом параметре этой функции передаётся строка в JSON формате с адресом страницы и количеством публикаций.<br />
В результате, в обработчик запроса будет передан JS объект с нужными данными. В этом примере он называется <code>response</code>, т.е. получить количество публикаций ссылки можно с помощью вызова <code>response.shares</code>.</p>
<p>В случае с вконтаке всё сложнее. Эта социальная сеть JSONP не поддерживает и на запрос</p>
<pre class="brush: javascript">$.getJSON('http://vkontakte.ru/share.php?act=count&#038;index=1&#038;url='
	+ encodeURI(page_url) + '&#038;callback=?', function(response) {});</pre>
<p>отвечает следующей строкой:</p>
<pre class="brush: javascript">VK.Share.count(1, 9);</pre>
<p>Естественно, это приводит к возникновению ошибки</p>
<p><code>VK is not defined</code></p>
<p>Вообще ответ сервера вконтакте – это обычный вызов метода count, присвоенного параметру <code>Share</code> объекта <code>VK</code>. Откуда берется этот объект? Его создаёт скрипт, который нужно подключить при использовании стандартного виджета. Но этот скрипт нам не нужен, т.к. виджет мы не используем, а количество публикаций ссылки нужно вставить в заранее подготовленный блок о котором стандартный скрипт ничего не знает.</p>
<p>Т.е. нам нужен собственный объект VK с соответствующими параметрами. Создать его совсем не сложно.</p>
<pre class="brush: javascript">var VK = {
    Share: {
        count: function(value, count) {
            $('#vkontakte_count').html(count);
        }
    }
}</pre>
<p>Теперь, после получения ответа от сервера вконтакте, будет вызвана анонимная функция, установленная для параметра <code>count</code>. Во втором параметре она получит количество публикаций страницы.</p>
<p>Обратите внимание – этот код должен находится в глобальной области видимости.</p>
<p>Привожу весь код целиком.</p>
<p>Страницы со счетчиками</p>
<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Счетчики&lt;/title&gt;
    &lt;meta charset="utf-8" /&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div&gt;Facebook &lt;span id="facebook_count"&gt;&lt;/span&gt;&lt;/div&gt;
    &lt;div&gt;ВКонтакте &lt;span id="vkontakte_count"&gt;&lt;/span&gt;&lt;/div&gt;

    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"&gt;&lt;/script&gt;
    &lt;script src="social_counters.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Скрипт social_counters.js</p>
<pre class="brush: javascript">jQuery(document).ready(function($) {
    var fb_counter = 0;
    var vk_counter = 0;
    var page_url = 'http://www.smashingmagazine.com/';

	$.getJSON('http://vkontakte.ru/share.php?act=count&#038;index=1&#038;url='
		+ encodeURI(page_url) + '&#038;callback=?', function(response) {});

	$.getJSON('http://graph.facebook.com/' + encodeURI(page_url)
			+ '&#038;callback=?', function(response) {
		if (response.shares !== undefined) {
			fb_counter = response.shares;
		}
		$('#facebook_count').html(response.shares);
	});
});

var VK = {
    Share: {
        count: function(value, count) {
            $('#vkontakte_count').html(count);
        }
    }
}</pre>
<h2>В заключение пара замечаний</h2>
<p>1) Поддержка JSONP значительно упрощает жизнь разработчикам и в конечном итоге способствует популяризации социальной сети или сервиса.</p>
<p>2) Отсутствие этой поддержки не означает, что вы не сможете интегрировать ваш сайт с данной социальной сетью. Главное, чтобы была возможность получить нужные данные в какой-нибудь форме. Естественно, при этом придётся написать какое-то количество дополнительного кода.</p>
<p>Если вы заметили ошибку или знаете более удачное решение данной проблемы, пишите, будет интересно обсудить.<br />
<strong>Успехов!</strong></p>
<p><strong>Интересно почитать</strong></p>
<p>Не знаете, <a href="http://imagebook.ru/chto_podarit_podruge">что подарить подруге на день рождения</a>? Фотоальбом с ее лучшими снимками!</p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/N8-ooQ2W-xM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/javascript-xss-poluchenie-dannyx-ot-facebook-i-vkontakte.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Список докладов и финальная регистрация ZFConf 2011 — второй российской конференции по Zend Framework</title>
		<link>http://www.simplecoding.org/zfconf-2011.html</link>
		<comments>http://www.simplecoding.org/zfconf-2011.html#comments</comments>
		<pubDate>Fri, 06 May 2011 06:15:39 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Разное]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1208</guid>
		<description><![CDATA[Основные подготовительные работы по конференции закончены. Доклады сформированы. Среди спикеров представители KnpLabs, Magento, JetBrains, Sphinx и других известных компаний. Открыта финальная регистрация! Если Вы проходили предварительную регистрацию, то для прохождения финальной регистрации Вам нужно перейти по специальной ссылке, отправленной на e-mail. Введенную ранее информацию нужно будет только подтвердить. Если ссылка не приходила Вам, ее можно [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1209" class="wp-caption alignnone" style="width: 202px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/05/zfconf-2011.jpg" alt="zfconf 2011" title="zfconf 2011" width="192" height="139" style="float:left" class="size-full wp-image-1209" /><p class="wp-caption-text"> </p></div>
<p>Основные подготовительные работы по конференции закончены. Доклады сформированы. Среди спикеров представители KnpLabs, Magento, JetBrains, Sphinx и других известных компаний.</p>
<p>Открыта <a href="http://www.zfconf.ru/registration/" target="_blank"><strong>финальная регистрация</strong></a>!</p>
<p><strong>Если Вы проходили предварительную регистрацию</strong>, то для прохождения финальной регистрации Вам нужно перейти по специальной ссылке, отправленной на e-mail. Введенную ранее информацию нужно будет только подтвердить. Если ссылка не приходила Вам, ее можно запросить через <a href="http://www.zfconf.ru/get-registration-path/" target="_blank">специальную форму</a>.</p>
<p>Пожалуйста, обратите внимание на то, что <strong>изменилось <a href="http://www.zfconf.ru/2011/location/" target="_blank" >место проведения</a></strong>! Мероприятие будет проходить на прошлогодней площадке — в актовом зале ЛГТЦ (Ленгипротранс-Центр), по адресу: Московский пр., 143, ст. м. «Электросила». Кофе-брейки и обсуждения на флипчартах будут проходить в фойе.</p>
<p><strong>Cписок докладов:</strong><br />
<span id="more-1208"></span><br />
<strong><a href="http://www.zfconf.ru/2011/topics/flexible-architecture-using-dependency-injection/" target="_blank">Гибкая архитектура Zend Framework приложений с использованием Dependency Injection</a></strong> </p>
<p>Алексей Качаев (<a href="http://cogniance.com/" target="_blank" >Сogniance</a>, Senior PHP Developer)</p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/performance-increasing-with-phpdaemon-varnish-esi/" target="_blank">Воюем за ресурсы: Повышение производительности Zend Framework приложения с помощью phpDaemon, Varnish и ESI</a></strong> </p>
<p>Алексей Качаев (<a href="http://cogniance.com/" target="_blank" >Сogniance</a>, Senior PHP Developer)</p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/behavior-driven-development/" target="_blank">Behavior Driven Development в PHP и Zend Framework</a></strong> </p>
<p>Константин Кудряшов (<a href="http://www.knplabs.com/" target="_blank" >KnpLabs</a>, Senior Web Developer)</p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/multitasking-distributed-system-with-job-queue/" target="_blank">Разделение труда: Организация многозадачной, распределенной системы в Zend Framework с помощью Job Queue</a></strong> </p>
<p>Александр Готгельф (<a href="http://www.magentocommerce.com/" target="_blank" >Magento</a>, PHP-разработчик) </p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/how-can-help-development-environment/" target="_blank">Как может помочь среда разработки при написании приложения на Zend Framework?</a></strong> </p>
<p>Николай Матвеев (<a href="http://www.jetbrains.com/" target="_blank" >JetBrains</a>, разработчик) </p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/creating-rest-api-for-third-party-developers-and-mobile-devices-with-oauth/" target="_blank">Создание REST-API для сторонних разработчиков и мобильных устройств с авторизацией по протоколу OAuth 1.0</a></strong> </p>
<p>Дмитрий Чижевский (<a href="http://zenmoney.ru/" target="_blank" >Дзен-мани</a>, разработчик) </p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/fat-model-through-orm-development-history/" target="_blank">Толстая модель: История разработки собственного ORM</a></strong> </p>
<p>Михаил Шамин (<a href="http://geometria.ru/" target="_blank" >Геометрия</a>, ведущий разработчик) </p>
<p><strong><a href="http://www.zfconf.ru/2011/topics/what-is-sphinx-and-how-use-it-with-php/" target="_blank">Что такое Sphinx, зачем он вообще нужен и как его использовать с PHP (от простого индекса до поискового кластера)</a></strong> </p>
<p>Владимир Федорков (<a href="http://sphinxsearch.com/" target="_blank" >Sphinx</a>, Director of Professional Services)</p>
<p>Стоимость участия в мероприятии составит 1500 руб. В данную сумму входит: участие в самой конференции, кофе-брейки (от внешней кейтеринг-компании), пакет материалов участника и доступ к профессиональным видеозаписям докладов (после мероприятия). Доступно <a href="http://www.zfconf.ru/payment-types/" target="_blank" >множество способов оплаты</a>.</p>
<p>Торопитесь, <strong>количество мест ограничено</strong>!</p>
<p>Обязательно следите за последними новостями:<br />
<strong>RSS-канал:</strong> <a href="http://feeds.feedburner.com/zfconf" target="_blank">feeds.feedburner.com/zfconf</a><br />
<strong>Twitter:</strong> <a href="http://twitter.com/zfconf" target="_blank">@zfconf</a><br />
<strong>Группа ВКонтакте:</strong> <a href="http://vkontakte.ru/club14951507" target="_blank">vkontakte.ru/club14951507</a></p>
<p><strong>Организатор:</strong> <a href="http://www.wizartech.ru/" target="_blank">компания Wizartech</a><br />
<strong>Партнеры:</strong> <a href="http://zendframework.ru/" target="_blank">сообщество zendframework.ru</a> и <a href="http://zfconf.org.ua/" target="_blank">конференция ZFConf Ukraine</a></p>
<img src="http://feeds.feedburner.com/~r/simplecoding/~4/TIf-RnAeI6M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/zfconf-2011.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

