<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>ZetBlog&#187; PHP</title>
	<atom:link href="http://zetblog.ru/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://zetblog.ru</link>
	<description>Зеты говорят. Блог о программировании, администрировании и безопасности.</description>
	<lastBuildDate>Sat, 29 Oct 2011 18:59:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>WordPress: Модернизация плагина statpress.</title>
		<link>http://zetblog.ru/programming/201002/wordpress-statpress-russian-optimization/</link>
		<comments>http://zetblog.ru/programming/201002/wordpress-statpress-russian-optimization/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 09:59:08 +0000</pubDate>
		<dc:creator>lizz</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[StatPress]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=948</guid>
		<description><![CDATA[Статистика &#8212; вещь не только интересная, но иногда и полезная :). WordPress &#8212; один из популярнейших движков php для блогов, для него существует огромное количество плагинов, в том числе и плагины для просмотра статистики по посещаемости. Один из таких плагинов &#8212; statpress. Но есть в нём некоторые недостатки, автор плагина добавил распознавание некоторых русских поисковых [...]]]></description>
			<content:encoded><![CDATA[<p>Статистика &#8212; вещь не только интересная, но иногда и полезная :). WordPress  &#8212; один из популярнейших движков php для блогов, для него существует огромное количество плагинов, в том числе и плагины для просмотра статистики по посещаемости. Один из таких плагинов &#8212; statpress. Но есть в нём некоторые недостатки, автор плагина добавил распознавание некоторых русских поисковых движков, но так же некоторые упустил из виду. Хотя даже тот же Яндекс обрабатывается не очень хорошо, не учитываются переходы с yandex.ua, yandex.kz и т.п. Но opensource тем и хорош, что всегда можно поправить исходники, если что-то тебя не устраивает :). Далее пойдёт речь об оптимизации плагина statpress под Российские поисковики.<br />
<span id="more-948"></span></p>
<p>В общем надоело мне то, что не учитывается часть поисковиков, надоело смотреть на ссылки с этих поисковиков в &#171;последних ссылающихся ресурсах&#187;, как оказалось, подправить это доваольно легко. С недельку ещё последил для отлова поисковых движков, и вот примерный список улучшений:</p>
<ul>
<li><strong>Yandex</strong> &#8212; улучшено поддержка (теперь распознаётся yandex.kz, yandex.ua. В общем то теперь маска для яндекса выглядит так: yandex.*, в связи с этим так же распознаются переходы вида yandex.ru/schoolsearch?text=* и т.п.);</li>
<li><strong>Nigma</strong> &#8212; добавлена поддержка поисковика nigma.ru</li>
<li><strong>Go Mail.ru</strong> &#8212; добавлена поддержка поисковика Go от Mail.Ru</li>
<li><strong>QIP</strong> &#8212; добавлена поддержка поисковика от QIP&#8217;а</li>
<li><strong>bing.</strong> &#8212; добавлен поисковик bing.com</li>
<li><strong>Rambler</strong> &#8212; улучшена поддержка поисковика от Рамблера</li>
</ul>
<p>Так же из &#171;ссылающихся ресурсов&#187; убараны ссылки вида &#171;*google.*&#187;, если это нововведение вам не нужно, не заменяйте в своём плагине файл statpress.php. У меня почему-то появилась куча ссылок на меня с гугла, по которым находится что-то вроде &#171;ресурс zetblog.ru пытается перенаправить вас&#187;. В случае обновления statpress.php такая проблема исчезнет, но могут так же пропасть и нужные ссылки с google (если они есть вообще).</p>
<p>После обновления файлов плагина необходимо обновить БД статистики (достаточно долгий процесс&#8230; особенно если база большая), делается это через админку wordpress путём одинарного клика по кнопке StatPressUpdate ^__^.</p>
<p>Если что-то какие-то поисковики упустил &#8212; пишите в комменты, обновлю. Ну, либо сам, если узнаю об этом :). Надеюсь, кому-то это поможет.</p>
<p>Ссылки на скачивание всего этого:<br />
<a href="http://depositfiles.com/files/3lujgxn3d">http://depositfiles.com/files/3lujgxn3d</a> &#8212; плагин полностью на депозите.<br />
Позже (по первой просьбе или как дойдут руки)) добавлю ссылку на скачивание с этого ресурса.</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/201002/wordpress-statpress-russian-optimization/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PHP: Пример использования ORM Doctrine.</title>
		<link>http://zetblog.ru/programming/200905/php-orm-doctrine-simple-example/</link>
		<comments>http://zetblog.ru/programming/200905/php-orm-doctrine-simple-example/#comments</comments>
		<pubDate>Wed, 20 May 2009 10:35:25 +0000</pubDate>
		<dc:creator>lizz</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=700</guid>
		<description><![CDATA[В данном посте рассмотрим простенький пример использования ORM, а именно, Doctrine. Если кто не в курсе, то ORM (Object-Relational Mapping, объектно-реляционная проекция) &#8212; такая штука, которая обеспечивают классам прозрачный доступ к базе данных. Правда не всяким классам, а тем, которые представляют описание нашей модели данных. В общем мне бы пару лет назад узнать о такой [...]]]></description>
			<content:encoded><![CDATA[<p>В данном посте рассмотрим простенький пример использования ORM, а именно, Doctrine. Если кто не в курсе, то ORM (Object-Relational Mapping, объектно-реляционная проекция) &#8212; такая штука, которая обеспечивают классам прозрачный доступ к базе данных. Правда не всяким классам, а тем, которые представляют описание нашей модели данных. В общем мне бы пару лет назад узнать о такой штуке, может быть я и не забросил изучение php, и вообще, много чего полезного сделал :D. Если кто-то знаком с паттернами проектирования, то можно сказать, что Doctrine соответствует шаблону Active Record. К своему стыду, сам я не знаком с ними, поэтому ничего конкретней сказать не могу пока что :-).</p>
<p>Кстати, мы уже затрагивали мельком тему ORM, но только для python. Можете посмотреть <a href="http://zetblog.ru/tag/sqlalchemy/">тут</a> про SQLAlchemy.</p>
<p>Далее будет рассмотрен пример написания модуля на php с использованием ORM Doctrine для отправки личных сообщений между пользователей.<br />
<span id="more-700"></span></p>
<p>Для начала определимся с нашей таблицей. Я решил использовать всего одну табличку, и для каждого сообщения так же хранить только одну запись в БД. И так, поля таблицы выглядят у меня примерно следующим образом:</p>
<ul>
<li>id &#8212; id сообщения;</li>
<li>uid_from &#8212; id отправившего пользователя;</li>
<li>uid_to &#8212; id получателя;</li>
<li>title &#8212; заголовок сообщения;</li>
<li>text &#8212; текст сообщения;</li>
<li>flag_unread &#8212; флаг нового сообщения;</li>
<li>flag_del_from &#8212; признак удалённого сообщения из исходящих;</li>
<li>flag_del_to &#8212; признак удалённого сообщения из входящих;</li>
<li>date &#8212; дата отправки в формате unix timestamp;</li>
</ul>
<p>На этом этап проектирования у меня закончился :). Теперь перейдём к технической стороне вопроса.</p>
<p>Качаем тот самый Doctrine (ссылка в конце поста), находим в архиве директорию, где лежит файл Doctrine.php и копируем всё содержимое этого каталога в отдельную папку в нашем проекте (я скопировал в doctrine). Следуя документации, создаём файл bootstrap.php в корне проекта с таким содержанием:</p>
<pre class=".brush: php">&lt;?php
require_once(dirname(__FILE__) . '/doctrine/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_CONSERVATIVE);
$manager->setAttribute(Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true);
$manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_ALL);
$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);
$manager->setAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER, true);
$user = 'tst';
$password = 'tst';
$host = 'localhost';
$db = 'tst';
$dsn = "mysql://$user:$password@$host/$db";
$conn = Doctrine_Manager::connection($dsn);
Doctrine::loadModels('models');
?></pre>
<p>Тут настраивается подключение к БД и некоторые параметры (&#171;ленивый&#187; способ загрузки моделей, валидация данных и т.п.). Последняя строчка указывает Doctrine где искать наши модели.</p>
<p>Теперь в корне проекта создаём папку models и в ней файл PrivateMessage.php. Учтите, что имя файла и класса, который описан в нём, должны совпадать. Вот как у меня выглядит этот файл:</p>
<pre class=".brush: php">&lt;?php
class PrivateMessage extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('uid_from', 'integer', 8, array(
				'unsigned' => true,
				'notnull' => true
			)
		);
        $this->hasColumn('uid_to', 'integer', 8, array(
				'unsigned' => true,
				'notnull' => true
			)
		);
        $this->hasColumn('title', 'string', 128);
        $this->hasColumn('text', 'string', 255);
        $this->hasColumn('flag_unread', 'boolean', array(
        		'default' => false,
				'notnull' => true
			)
		);
	$this->hasColumn('flag_del_from', 'boolean', array(
				'notnull' => true,
				'default' => false
			)
		);
	$this->hasColumn('flag_del_to', 'boolean', array(
				'notnull' => true,
				'default' => false
			)
		);
        $this->hasColumn('date', 'integer', 8, array(
        		'notnull' => true,
				'default' => time()
			)
		);
    }
}
?></pre>
<p>Тут мы не описали поле id, т.к. Doctrine создаст его автоматически, если не указано других первичных ключей (primary key). Так же в таблице не указаны индексов, что не есть хорошо. Неплохо было бы сделать их для полей uid_from и uid_to хотя бы. Но не сделаем, ибо лень, как-нибудь в другой раз ;-).</p>
<p>Следующим шагом создаём в корне проекта файл test.php, в котором будут описаны основные функции для работы с личными сообщениями и некоторый код для демонстрации функционала. Вот содержимое этого файла:</p>
<pre class=".brush: php">&lt;?php
require_once('bootstrap.php');
$conn->export->exportClasses(array('PrivateMessage'));
#FIXME: Set current user ID from session.
$curr_uid = 1;
function get_messages($inbox, $uid) {
	/*
	 * If $inbox == true then returns inbox of user $uid,
	 * else returns outbox.
	 */
	if($inbox) {
		$q = 'pm.uid_to = ? AND pm.flag_del_to = ?';
	} else {
		$q = 'pm.uid_from = ? AND pm.flag_del_from = ?';
	}
	return Doctrine_Query::create()
    	->from('PrivateMessage pm')
    	->where($q, array($uid, 0))
    	->fetchArray();
}

function get_message($id, $uid) {
	$q = Doctrine_Query::create()
    	->from('PrivateMessage pm')
    	->where('pm.id = ? AND (pm.uid_from = ? OR pm.uid_to = ?)', array($id, $uid, $uid));
    	$q = $q->fetchArray();
    	if(count($q)) {
    		if($uid == $q[0]['uid_to'] &#038;&#038; $q[0]['flag_unread']) {
    			Doctrine_Query::create()
				    ->update('PrivateMessage pm')
    				->set('pm.flag_unread', '?', false)
 			   		->where('pm.id = ?', $q[0]['id'])
 			   		->execute();
    		}
    		return $q[0];
    	} else {
    		return false;
    	}
}

function delete_messages($ids, $uid) {
	/*
	 * $ids - array of ids of messages, that will be deleted.
	 * $uid - current user id.
	 * P.S. Broken English - is the most popular language in the world ;-).
	 */
	foreach($ids as $id) {
		Doctrine_Query::create()
			->update('PrivateMessage pm')
			->set('pm.flag_del_to', '?', true)
 			->where('pm.id = ? AND pm.uid_to = ?', array($id, $uid))
 			->execute();
 		Doctrine_Query::create()
			->update('PrivateMessage pm')
			->set('pm.flag_del_from', '?', true)
 			->where('pm.id = ? AND pm.uid_from = ?', array($id, $uid))
 			->execute();
	}
	Doctrine_Query::create()
		->delete('PrivateMessage pm')
 		->where('pm.flag_del_from = 1 AND pm.flag_del_to = 1')
 		->execute();
}

function send_message($to, $title, $text, $uid) {
	$pm = new PrivateMessage();
	$pm->uid_from = $uid;
	$pm->uid_to = $to;
	$pm->title = $title;
	$pm->text = $text;
	$pm->flag_unread = true;
	// Если хранить в исходящих ненадо,
	// то можно установить следующий флаг в true.
	$pm->flag_del_from = false;
	$pm->flag_del_to = false;
	$pm->save();
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru" xml:lang="ru">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
&lt;?php
echo 'Current user:' . $curr_uid;
// Send message section.
if((int)@$_REQUEST['to'] &#038;&#038; !@empty($_REQUEST['title']) &#038;&#038; !@empty($_REQUEST['text'])) {
	send_message((int)$_REQUEST['to'], $_REQUEST['title'], $_REQUEST['text'], $curr_uid);
}
// End of send message section.

// Delete messages section.
if(@count($_REQUEST['del_messages'])) {
	echo '
<pre>';
	delete_messages($_REQUEST['del_messages'], $curr_uid);
	echo '</pre>
<p>';<br />
}<br />
// End of delete messages section.</p>
<p>// Inbox section.<br />
?></p>
<hr/>Inbox:</p>
<form name="del_messages" action="" method="post">
<table border="1">
<tr>
<td>Del</td>
<td>Message ID</td>
<td>Date</td>
<td>From</td>
<td>Title</td>
</tr>
<p>&lt;?php<br />
$m = get_messages(true, $curr_uid);<br />
foreach($m as $message) {<br />
	// Mark as bold unread messages.<br />
	if($message['flag_unread']) {<br />
		$b_open = '<b>';<br />
		$b_close = '</b>';<br />
	} else {<br />
		$b_open = '';<br />
		$b_close = '';<br />
	}<br />
	// End mark.<br />
	echo "<br />
<tr>
<td>
<input type=\"checkbox\" name=\"del_messages[]\" value=\"$message[id]\"/></td>
<td><a href=\"?message_id=$message[id]\">$b_open$message[id]$b_close</a></td>
<td>$b_open" . date('d.m.y H:i', $message['date']) . "$b_close</td>
<td>$b_open$message[uid_from]$b_close</td>
<td>$b_open$message[title]$b_close</td>
</tr>
<p>";<br />
}<br />
?></p>
<tr>
<td colspan="5">
<input type="submit" value="Delete selected"/></td>
</tr>
</table>
<p>&#038;lt?php<br />
// End of inbox section.</p>
<p>// Outbox section.<br />
?></p>
<hr/>Outbox:</p>
<table border="1">
<tr>
<td>Del</td>
<td>Message ID</td>
<td>Date</td>
<td>To</td>
<td>Title</td>
</tr>
<p>&lt;?php<br />
$m = get_messages(false, $curr_uid);<br />
foreach($m as $message) {<br />
	// Mark as bold unread messages.<br />
	if($message['flag_unread']) {<br />
		$b_open = '<b>';<br />
		$b_close = '</b>';<br />
	} else {<br />
		$b_open = '';<br />
		$b_close = '';<br />
	}<br />
	// End mark.<br />
	echo "<br />
<tr>
<td>
<input type=\"checkbox\" name=\"del_messages[]\" value=\"$message[id]\"/></td>
<td><a href=\"?message_id=$message[id]\">$b_open$message[id]$b_close</a></td>
<td>$b_open" . date('d.m.y H:i', $message['date']) . "$b_close</td>
<td>$b_open$message[uid_to]$b_close</td>
<td>$b_open$message[title]$b_close</td>
</tr>
<p>";<br />
}<br />
?></p>
<tr>
<td colspan="5">
<input type="submit" value="Delete selected"/></td>
</tr>
</form>
</table>
<p>?><br />
// End of outbox section.</p>
<p>// View message section.<br />
if((int)@$_REQUEST['message_id']) {<br />
	$m = get_message($_REQUEST['message_id'], $curr_uid);<br />
	if($m !== false) {<br />
		echo "<br />
<hr/>View message #$m[id]:";<br />
		echo '<br />
<table border="1">';<br />
		echo "<br />
<tr>
<td>From:</td>
<td>$m[uid_from]</td>
</tr>
<tr>
<td>To:</td>
<td>$m[uid_to]</td>
</tr>
<tr>
<td>Title:</td>
<td>$m[title]</td>
</tr>
<tr>
<td>Message:</td>
<td>$m[text]</td>
</tr>
</table>
<p>";<br />
	}<br />
}<br />
// End of view message section.</p>
<p>// Send message section.<br />
echo "</p>
<hr/>New message:</p>
<table border="1">
<form action="" method="post" name="send_message">
<tr>
<td>From:</td>
<td>$curr_uid</td>
</tr>
<tr>
<td>To:</td>
<td>
<input name="to"/></td>
</tr>
<tr>
<td>Title:</td>
<td>
<input name="title"/></td>
</tr>
<tr>
<td>Message:</td>
<td><textarea name="text"></textarea></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="send message"></td>
</tr></form>
</table>
<p>";<br />
// End of send message section.<br />
?><br />
</body><br />
</html></pre>
<p>$conn->export->exportClasses(array(&#8216;PrivateMessage&#8217;)) &#8212; это строка создаст таблицу private_messaages, если таковой ещё нет. Так что можно её перенести в установочный скрипт, но поскольку у нас нет такого, то мы её оставим.<br />
$curr_uid &#8212; эта переменная по идее должна браться из сессии. Как она должна называться в сессии я не знал, поэтому присвоил ей значение в коде 1.<br />
get_messages($inbox, $uid) &#8212; возвращает все входящие сообщения пользователя $uid, если $inbox равна true, иначе &#8212; исходящие. Неплохо было бы добавить лимит на выборку записей (например, с 1й по 20ю, с 21й по 40ю), но поскольку этот модуль нигде применять не планирую, то и доделывать его нет желания. Если кому то надо &#8212; пишите в комменты ;-).<br />
get_message($id, $uid) &#8212; возвращает сообщение $id, $uid передаётся во все функции для проверки принадлежности сообщений текущему пользователю. Ещё раз повторю, идентификатор ползьователя должен браться из сессии.<br />
delete_messages($ids, $uid) &#8212; $ids &#8212; массив id&#8217;шников сообщений, которые надо удалить. Реально удаляются записи из БД только те, у которых flag_del_from и flag_del_to равны 0.<br />
send_message($to, $title, $text, $uid) &#8212; $to &#8212; id получателя, $uid &#8212; отправителя, остально думаю понятно.<br />
Дальше по коду идёт часть с html-выводом и обработкой переданных парамтеров, так что ничего интересного. Код по моему везде достаточно просто, так что подробно объяснять не стал. Если вопросы остались &#8212; в комменты.</p>
<p>P.S. Это моя первая попытка сделать что-либо с использованием Doctrine :).<br />
Ссылки к статье:<br />
<a href="http://ru.wikipedia.org/wiki/ORM">http://ru.wikipedia.org/wiki/ORM</a> &#8212; ORM;<br />
<a href="http://www.doctrine-project.org/">http://www.doctrine-project.org/</a> &#8212; официальный сайт проекта Doctrine.</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200905/php-orm-doctrine-simple-example/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

