+ All Categories
Home > Documents > #19, 2007 :: Путь к оптимизации MySQL

#19, 2007 :: Путь к оптимизации MySQL

Date post: 07-Mar-2016
Category:
Upload: vital-b
View: 230 times
Download: 0 times
Share this document with a friend
Description:
Цикл статей по оптимизации MySQL Инженерный анализ БД MySQL с DBDesigner Что такое XML Sapiens? Шифрование в PHP для обычных людей
53
#19' 2007 Путь к оптимизации MySQL Что такое XML Sapiens? Шифрование в PHP Введение в сокеты
Transcript
Page 1: #19, 2007 :: Путь к оптимизации MySQL

#19' 2007

Путь к оптимизации MySQL

Что такое XML Sapiens?

Шифрование в PHP

Введение в сокеты

Page 2: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Readme

ReadmeЭто readme я хотел бы посвятить двум вещам – поздравлениям с новым годом и рождеством, а также другой, не менее важной для нашей редакции теме – регулярности выпусков «PHP Inside» в новом 2007 году.

Сначала о праздниках. Редакция журнала и все-все-все кто участвовал в его создании поздравляют наших читателей с прошедшими праздниками! Мы надеемся, что новый год будет счастливым и успешным. Еще бы! Ведь по прогнозам британских аналитиков, РНР-программисты не зря выбрали эту стезю и будут пользоваться спросом на рынке труда. Хочется верить, что не только британского.

Нельзя не отметить, что каждый новый год для нас это не только праздники, фейерверки, бешенная гонка или расслабление (в зависимости от проектов, над которыми сейчас идет работа), но и очередной юбилей нашего журнала. Ведь именно перед новым годом на http://phpclub.ru появился топик с предложением создать PDF-журнал о любимой технологии, а в январе пилотный выпуск и создавался. Это был канун 2004 года, значит, с тех пор прошло уже добрых три года, за которые в свет вышло аж 20 номеров электронного журнала (включая текущий). И пусть вас не смущает, что этот номер носит гордую цифру «19» на своей обложке, ведь настоящие программисты начинают считать с нуля, поэтому, журнал для программистов был просто обязан начаться с выпуска №0. К этой веселой компании прибавляется еще и бумажный выпуск журнала, посвященный PHPConf 2006.

В прошедшем 2006 году мы вышли в эфир всего три раза. Начиная с нового года, мы планируем выходить тоже нечасто, но регулярно – раз в квартал (т.е. раз в три месяца). Все остальное время читайте новости и обзоры на http://phpinside.ru.

Андрей Олищук [nw]

в н о м е р е :

Новости и обзоры

*** Использование GROUP_CONCAT

в GROUP BY***

Оптимизируем ORDER BY … LIMIT***

Постоянные соединения с MySQL – зло?

*** UNION для увеличения произво­

дительности***

Инженерный анализ БД MySQL с DBDesigner

*** Не забудьте про данные!

*** Введение в сокеты

*** Как выбирать хостинг?

*** Интервью с Andrei Zmievski

*** Интервью: Chris Shiflett

*** Интерактивный грид своими ру­

ками***

Что такое XML Sapiens?***

Шифрование в PHP для обычных людей

45

Page 3: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Новости и обзоры >> PHPConf 2007!

PHPConf 2007!6-я Международная конференция "Современные технологии эффективной разработки веб-приложений с использованием PHP" (май 2007г.)

Текущий анализ рынка информационных технологий показывает все большую востребованность приложений с использованием веб-интерфейсов. В связи с этим повышается актуальность эффективных средств разработки программных продуктов для Интернета и корпоративных Интранет/Экстранет сетей. Одну из лидирующих позиций в этой сфере занимает PHP – популярный и бурно развивающийся язык веб-программирования.

Международный клуб веб-разработчиков PHPClub с 2003 года проводит конференции, посвященные разнообразным аспектам применения веб-технологий и собирающие ведущих разработчиков, IT-директоров, аналитиков и менеджеров проектов со всего мира. Подобные мероприятия – это новые идеи, современные методики производства программного обеспечения, опыт успешного внедрения программных решений, тенденции развития отрасли и, наконец, живое общение.

Приглашаем вас принять участие в очередной конференции, которая состоится мае 2007 года в г. Москве.

Тематика конференции- Эффективное применение PHP в веб-разработке. Приёмы, методы и парадигмы программирования в PHP, полезные модули и библиотеки, интеграция с Ajax.

- Эффективное создание приложений. Frameworks, гибкие методологии, экстремальное программирование, ТDD-методики.

- PHP и корпоративные информационные системы. Разработка систем масштаба предприятия, интеграция корпоративных ИС.

- Будущее PHP. Основные направления развития, PHP6, мультиязычные приложения, Unicode, применение в условиях Web 2.0

Приглашаем докладчиков!Кто будет выступать?

Организационный комитет приглашает выступить профессиональных веб-разработчиков, имеющих солидный практический опыт в сфере затрагиваемых на конференции тем.

Каков должен быть доклад?

Устное выступление автора рассчитано на 30-60 минут. Приветствуются доклады, основанные на реальных проектах.

Page 4: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Новости и обзоры >> PHPConf 2007!

Как подать заявку?

Авторам, желающим принять участие в конференции с устным докладом, необходимо до 1 февраля 2007 года отправить тезисы доклада объемом в одну(две) страницы, отражающие содержание представляемого доклада. На основе тезисов будет проведен отбор докладов для включения в программу конференции. Авторы докладов, прошедших рецензирование, будут уведомлены после 15 февраля и получат второе информационное сообщение с правилами оформления электронных версий докладов. Тезисы докладов (в виде стандартного .doc или .txt файла произвольной формы) принимаются оргкомитетом по электронному адресу [email protected]

Приглашаем спонсоров!К участию в конференции мы приглашаем организации, желающие закрепить статус лидеров в IT-сфере. PHPCONF 2007 – отличная возможность выйти на контакт с уникальной аудиторией веб-разработчиков. Предлагаемыми формами участия в конференции являются различные статусы спонсорства.

По всем вопросам, связанным с участием в конференции в качестве спонсора, пожалуйста, обращайтесь в оргкомитет тел. (495) 744-31-18, email [email protected]

До встречи на PHPCONF 2007!

http://www.phpconf.ru/

Блог: Оптимизация MySQL

В сети по адресу http://www.mysqlperformanceblog.com/ работает блог, посвященный вопросам повышения производительности баз данных MySQL. Его ведут два наших соотечественника, независимые специалисты по оптимизации MySQL – Петр Зайцев и Вадим Ткаченко.

Среди статей встречаются как короткие заметки, так и полноценные исследования по вопросам повышения производительности. Вот некоторые из заголовков: «Тестирование

Page 5: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Новости и обзоры >> Блог: Оптимизация MySQL

производительности InnoDB», «Сессионные переменные и хинты в MySQL», «Использование LoadAvg в оптимизации» и так далее. В этом номере «PHP Inside» вы встретите переводы нескольких статей на русский язык.

Спрос на PHP-разработчиков в 2007 году будет высокимТак считают аналитики hiveminds.co.uk, основываясь на статистических выкладках itjobswatch.co.uk. Более того, РНР признается уже не просто "перспективной технологией", а производственной необходимостью в сфере веб-разработки. В аналитическом отчете приведены данные зарубежных исследований, однако, в России популярность PHP не меньше, чем в европейских странах, поэтому тренд можно распространять и на отечественные условия.

В результате, как полагают аналитики, спрос на PHP-разработчиков в 2007 году будет высоким. Рынок труда в 2006 году продемонстрировал стабильный рост спроса на разработчиков со знанием PHP, а в 2007 эта тенденция только усилится, так как этот язык веб-разработки уже вышел из тени Java и ASP.NET и работодатели, а также и сами программисты все больше видят в нем инструмент для реализации бизнес-целей. В целом, популярность языка стабильна и выходит на небольшой рост после падения с релизом его пятой версии. Ниже приведены таблицы соответственно: «Наиболее востребованные знания для PHP-разработчика помимо PHP» и «Рейтинг программ, которые также будут необходимы в работе».

Page 6: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Новости и обзоры >> XML Sapiens 2.0

XML Sapiens 2.0Red Graphic Systems (http://www.redgraphic.ru) опубликовала спецификацию XML Sapiens 2.0 (http://www.xmlsapiens.org), декларативного языка пользовательских интерфейсов веб-приложений. XML Sapiens позволяет описать веб-приложение как композицию абстрактных составляющих: данных, их оформления и функциональности. Язык призван сократить время на разработку и отладку веб-приложений.

В новой версии XML Sapiens расширены возможности по многократному использованию информационных объектов, сценариев, шаблонов, а также по их переносимости. XML Sapiens 2.0 открывает перед широким кругом веб-разработчиков путь к созданию проектов с более глубокой бизнес-логикой, насыщенной интерактивностью, эффективных проектов, близких пожеланиям пользователей. Для реализации веб-приложений на языке XML Sapiens разработчики могут воспользоваться бесплатным процессором языка или же собственным, написанным согласно указаниям спецификации языка.

В текущем номере «PHP Inside» читайте статью Дмитрия Шейко «Что такое XML Sapiens?».

Релиз PHProjekt 5.2Состоялся релиз PHProjekt 5.2 (http://www.phprojekt.com/index.php?&newlang=eng) - системы управления групповой деятельностью и обменом документами в сети. Программное обеспечение включает в себя компоненты группового календаря, управления проектами, учета отработанного времени, менеджер контактов и многое другое. Поддерживаются протоколы ldap, SOAP/XML и Webdav. В новой версии был переработан пользовательский интерфейс, встроена поддержка Dojo JavaScript Toolkit для работы в стиле Web 2.0 (хотя основные изменения пользовательского интерфейса обещаются в следующих релизах). Начиная с этого релиза система работает и с IBM DB2, которая стала девятой по счету поддерживаемой СУБД.

Важнейшие изменения в системе коснулись компонента Help Desk и разработчики утверждают, что теперь можно вести полноценный конфигурируемый рабочий процесс по оказанию техподдержки. Система локализована для России и некоторых других стран из бывшего СССР (необходимо скачать дополнение для некоторых кодировок).

Page 7: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Использование GROUP_CONCAT в GROUP BY

Использование GROUP_CONCAT в GROUP BYАвторы: http://mysqlperformanceblog.com, перевод: Андрей Олищук

В MySQL существует полезное расширение операции GROUP BY функция GROUP_CONCAT (в официальной документации - http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html).

Формат записи прост:

GROUP_CONCAT (выражение)

Данная функция возвращает строку результата с объединенными значениями из группы, не равными NULL. Шде это может пригодиться?

Для примера рассмотрим получение массива в PHP без введения циклов внутри самого PHP-кода.CREATE TABLE services (id INT UNSIGNED NOT NULL, client_id INT UNSIGNED NOT NULL, KEY (id));INSERT INTO services VALUES (1,1),(1,2),(3,5),(3,6),(3,7);

SELECT id,client_id FROM services WHERE id = 3;+----+-----------+| id | client_id |+----+-----------+| 3 | 5 | | 3 | 6 | | 3 | 7 | +----+-----------+

SELECT id,GROUP_CONCAT(client_id) FROM services WHERE id = 3 GROUP BY id; +----+-------------------------+| id | GROUP_CONCAT(client_id) |+----+-------------------------+| 3 | 5,6,7 | +----+-------------------------+

Что бы нам пришлось сделать на PHP в обычной ситуации:

CODE:<?php$res=$mysqli->query("SELECT id,client_id FROM services WHERE id = 3"); while ($row = $res->fetch_array(MYSQLI_ASSOC)) { $result[] = $row['client_id'];}$res->free();?>

Page 8: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Использование GROUP_CONCAT в GROUP BY

И в ситуации с group_concat:<?php$res=$mysqli->query("SELECT id,GROUP_CONCAT(client_id) as clients FROM services WHERE id = 3 GROUP BY id");$row = $res->fetch_array(MYSQLI_ASSOC)) $result = explode(',', $row['clients']; // $row['clients'] contains string 5,6,7$res->free();?>

Второе решение будет более быстрым, так как мы убираем лишние проходы по циклу средствами PHP и передаем эту задачу на более быстрый уровень MySQL.

Иногда бывает полезно использовать результат конкатенации в выражении IN:<?php$res=$mysqli->query("SELECT id,GROUP_CONCAT(client_id) as clients FROM services WHERE id = 3 GROUP BY id");$row = $res->fetch_array(MYSQLI_ASSOC)) $result = $row['clients']; // $row['clients'] contains string 5,6,7$res->free(); $resclients=$mysqli->query("SELECT id,client_name FROM clients WHERE id = IN ($result)");// handle $resclients ?>

Конечно, последний пример может быть реализован и с помощью JOIN, но иногда нам нужны временные ID в коде, к примеру в случаях выполнения запроса на другом сервере.

И последнее: иногда вы можете добавлять ORDER BY NULL после GROUP BY, чтобы избежать ненужной сортировки с filesort.

Page 9: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Оптимизируем ORDER BY … LIMIT

Оптимизируем ORDER BY … LIMITАвторы: http://mysqlperformanceblog.com, перевод: Андрей Олищук

Зачастую, реализация ORDER BY, особенно в паре с LIMIT, вызывает проблемы производительности в работе MySQL. В данной статье мы приводим факты, которые вам необходимо знать об ORDER BY ... LIMIT во избежание трудностей с производительностью.

Наиболее часто конструкция ORDER BY употребляется вместе с LIMIT в интерактивных приложениях с большими объемами сортированных данных. На многих сайтах вы можете встретить рейтинговые списки, к примеру - последних зарегистрированных пользователей и т.п. Такие списки практически всегда строятся на базе запросов с ORDER BY … LIMIT. В общих чертах, подобные запросы выглядят так: SELECT ..... WHERE [условие] ORDER BY [критерий сортировки] LIMIT N,M

Используйте индексыПрежде всего убедитесь, что используются индексы, т.е. ORDER BY … LIMIT выполняется без сканирования и сортировки всего набора данных в базе. В таком случае, начнется сканирование только индекса и выполнение запроса будет остановлено как только «достанется» необходимое количество записей.

К примеру, если я выполняю SELECT * FROM sites ORDER BY date_created DESC LIMIT 10 то я использую индекс поля date_created и результаты получаются быстрее.

Взглянем на такой запрос: SELECT * FROM sites WHERE category_id=5 ORDER BY date_created DESC LIMIT 10. В данном случае также задействуется индекс на date_created, но он будет не так эффективен, если в категории, в которой производится поиск по categoru_id содержится много записей. Хорошей идеей будет создание индекса на date_created и category_id.

Рассмотрим более сложный пример: SELECT * FROM sites WHERE category_id in (5,10,12)

SysBench для тестирования производительностиПрограммное обеспечение Sysbench разработано Алексеем Ко­пытовым, инженером-программистом из MySQL AB. Эту про­грамму (http://sysbench.sourceforge.net/) я использую в рабо­те каждый день и хотел бы написать несколько слов о ней. Начну с примера: компания SUN опубликовала сравнение сво­ей системы Solaris c RedHat, используя результаты SysBench (я и один мой коллега выступали в роли консультантов в этом тестировании). SysBench имеет внушительный список возмож­ностей, но здесь я остановлюсь на общем рассмотрении при­меров использования этой программы.

SysBench позволяет тестировать:

- Производительность файлового ввода/вывода.

- Производительность планировщика задач.

- Распределение памяти и скорость передачи.

- Производительность работы потоков POSIX.

- Производительность работы серверов баз данных.

Первые четыре пункта будут полезны для оценки различных платформ. К примеру для таких случаев, когда вы хотите сравнить скорость файлового ввода/вывода и работу потоков на различных серверах. Что касается тестирования серверов баз данных, то в версии 0.4.7 и ранних, SysBench поддержива­ла только предопределенный набор запросов, однако все из­менилось уже в версии 0.5, в которой стало возможным пи­сать собственные скрипты на языке Lua. Как следствие - в данной версии существует возможность тестирования на осно­ве собственных таблиц и запросов. Версия 0.5 выйдет в самом скором времени. Изначально, система поддерживала только MySQL, но позже были добавлени опции работы с Oracle и PostgreSQL (включая ответвления, к примеру EnterpriseDB). Данный факт не совсем отмечен в документации, но он оста­ется фактом.

SysBench использует только «родные» API, избегая промежу­точных слоев вроде ODBC, именно поэтому, список поддержи­ваемых СУБД не так широк. Еще одним ограничением SysBench является то, что ее нельзя скомпилировать на Windows, хотя вы, конечно, можете попытаться и написать нам о своем опыте.

Page 10: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Оптимизируем ORDER BY … LIMIT

ORDER BY date_created DESC LIMIT 10. На первый взгляд в нем нет ничего сложного по сравнению предыдущим, кроме как множественное указание значений category_id. Однако, здесь мы не можем напрямую задействовать индекс на category_id и date_created. Индекс date_created по прежнему будет работать. С точки зрения производительности (хоть это и выглядит немного уродливо) будет использование UNION для нескольких запросов.

Различные социальные сайты и службы знакомств являются превосходным примером для таких запросов: SELECT FROM people where gender='m' and age between 18 and 28 and country_id=5 and city_id=345 order by last_online desc limit 10;

Здесь встречается большое количество ограничивающих факторов, большинство которых являются еще и опциональными. В таких случаях, создание индексов для наиболее часто запрашиваемые поля будет хорошей идеей в целях увеличения производительности.

К примеру, вы можете создать индекс для gender и last_online при условии, что у большинства людей будет указан пол (gender). Так же, неплохо было бы создать индексы для country_id, city_id и last_online, рассчитывая на то, что поиск по этим параметрам будет проводиться довольно часто. Это заметно улучшит производительность, сократив время подготовки необходимой выборки данных.

Важно иногда проверять, сколько строк сканируется для завершения операции ORDER BY (эти данные можно найти в логе медленных запросов или изучая статистику Hander). Если для выборки 10 записей система просматривает 50, то вы находитесь в прекрасной форме. Однако, если количество увеличилось до 5000, то стоит задуматься о пересмотре политики индексирования.

На заметку: количество проверенных записей, необходимое для получения выборки по ORDER BY очень динамично и серьезно варьируется в зависимости от конкретных констант и других факторов. Если в приведенном выше примере с сайтом знакомств мы будем использовать только индекс last_online и будем искать людей только из США, то 10 записей найдутся очень быстро. Однако, если страна маленькая или из нее зарегистрировано мало пользователей (пример – Словения), то системе понадобится проверить в тысячи раз большее количество записей для подготовки выборки.

Не последнюю роль играет порядок следования полей в индексе. Рассмотрим пример:key(a,b,c) SELECT * FROM tbl WHERE c=5 ORDER BY a,b limit 10

В данном случае, первые два столбца из индекса подходят для ORDER BY, однако этот индекс не будет полезным для проверки условия c=5. Здесь было бы лучшим решением создать индекс (c,a,b).

Выражения в условии сортировкиНе используйте выражения для сортировки, так как они (и еще функции) блокируют использование индекса для ORDER BY.

Сортировка по столбцу из первой таблицыОсуществляйте сортировку по столбцу из таблицы, упомянутой первой, если используете JOIN вместе с ORDER BY ... LIMIT. Если сортировка ORDER BY осуществляется по полю не из первой

Page 11: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Оптимизируем ORDER BY … LIMIT

упомянутой в запросе с JOIN таблицы, то для нее механизм индексов не задействуется. Иногда это означает нарушение нормализации и дублирование столбцов, которые вы собираетесь использовать в ORDER BY другой таблицы.

Вот пример, когда ORDER BY выполняется по второй таблице, требующей filesort:

SQL:mysql> EXPLAIN SELECT test.i FROM test, test t WHERE test.k=5 AND test.i=t.k ORDER BY t.k LIMIT 5;1. +----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+2. | id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |3. +----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+4. | 1 | SIMPLE | test | ref | PRIMARY,k | k | 4 | const | 1 | USING TEMPORARY; USING filesort |5. | 1 | SIMPLE | t | ref | k | k | 4 | test.test.i | 1 | USING WHERE; USING INDEX |6. +----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+

Однако, если первая таблица имеет тип доступа “const” или “system”, она эффективно заменяется константами и, таким образом, ORDER BY может быть оптимизировано, даже если сортировка производится по второй таблице:

SQL:mysql> EXPLAIN SELECT test.i FROM test, test t WHERE test.i=5 AND test.k=t.k ORDER BY t.k LIMIT 5;+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+| 1 | SIMPLE | test | const | PRIMARY,k | PRIMARY | 4 | const | 1 | || 1 | SIMPLE | t | ref | k | k | 4 | const | 1 | USING INDEX |+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+

Разница заключается в том, что i является первичным ключем, в то время, как k это всего лиш обычный индекс.

Примечание: В некоторых случаях, не смотря на то, что существует возможность использования индексов для сортировки ORDER BY с JOIN, MySQL не всегда использует индексы, так как оптимизатор еще не настолько «умен» чтобы распознавать подобные ситуации.

SQL:7. mysql> EXPLAIN SELECT test.i FROM test, test t WHERE test.k=5 AND test.i=t.k ORDER BY test.k,t.j LIMIT 5;8. +----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+9. | id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |10. +----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+11. | 1 | SIMPLE | test | ref | PRIMARY,k | k | 4 | const | 1 | USING TEMPORARY; USING filesort |12. | 1 | SIMPLE | t | ref | k | k | 4 | test.test.i | 1 | USING WHERE; USING INDEX |13. +----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+14. 2 rows IN SET (0.00 sec)

В приведенном примере для таблицы существует индекс (k,j), поэтому индексы могут использоваться в каждой таблице для оптимизации ORDER BY, или, по крайней мере, для локальной сортировки значения t.k=const во второй таблице.

Проводите сортировку в одном направленииЕсли у вас есть запрос ORDER BY col1, col2, то в нем задействуются индексы. В запросе ORDER BY col1 DESC, col2 DESC они так же задействуются. Однако запрос ORDER BY col1, col2 DESC в MySQL вызовет необходимость использования filesort. Классическим решением данной проблемы является соответствующая сортировка на уровне самих индексов (по нарастающей для col1 и по убывающей для col2). Но в MySQL с этим пока есть проблемы. Обходным маневром может послужить использование отдельного столбца, хранящего значения в обратном порядке, чтобы вы смогли использовать ORDER BY col1, col2_reverse вместо прямого указания порядка сортировки в запросе.

Page 12: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Оптимизируем ORDER BY … LIMIT

Избегайте больших LIMITИспользование индекса для сортировки будет эффективно, если используются его первые строки. В любом случае, системе потребуется просканировать большее количество строк, чем вы указали в LIMIT. Отсюда следует, что при больших LIMIT страдает эффективность. LIMIT 1000,10 вероятнее всего будет медленнее чем LIMIT 0,10. В действительности, большинство пользователей поисковиков не просматривают более чем 10 страниц в результатах поиска, однако поисковые боты проходят все страницы до одной. Мне встречались боты, которые просматривали свыше 200 страниц с результатами поиска в моих проектах. В таких случаях открывается уязвимость для DOS-атак – запроса большого количества страниц с нескольких соединений будет достаточно. Поэтому, обязательно блокируйте запросы на большое количество страниц.

В некоторых случаях, к примеру, когда результаты статичны, то лучше будет рассчитать их позиции в базе и запрашивать по ID. Вместо LIMIT 1000,10, можно поставить условие WHERE c позициями от 1000 до 1009 и, если на ID существует индекс, производительность возрастет.

Форсируйте индексы, если это необходимоВ некоторых случаях, оптимизатор MySQL может предпочесть использовать тот индекс, который в данной ситуации поддается более легкой выборке. К примеру, если у вас есть индекс (country_id,city_id) и индекс (country_id,last_online) для запроса SELECT * FROM people WHERE country_id=5 and city_id=6 order by last_online desc limit 10 вероятнее всего будет использован первый индекс, хотя он и приведет к filesort.

Решением этой проблемы является расширение индексов, для того чтобы оптимизатор MySQL не выбирал между лучшей сортировкой или лучшим просмотром. Еще лучше – используйте FORCE INDEX, чтобы заставить систему использовать конкретный индекс.

Еще одно примечание по поводу ORDER BY ... LIMIT – данная конструкция выдает ужасные результаты для выражения explain и может попасть в лог медленных запросов, даже если выполняется быстро:mysql> EXPLAIN SELECT * FROM test ORDER BY k LIMIT 5;+----+-------------+-------+-------+---------------+------+---------+------+---------+-------+| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |+----+-------------+-------+-------+---------------+------+---------+------+---------+-------+| 1 | SIMPLE | test | INDEX | NULL | k | 772 | NULL | 1638400 | |+----+-------------+-------+-------+---------------+------+---------+------+---------+-------+1 row IN SET (0.03 sec)

Если мы посмотрим на графу «rows» («строки»), то увидим, что было проверено около 1.6 миллионов строк, хотя мы запрашивали всего пять в данном случае.

Большинство из приведенных выше советов подходят и для ORDER BY без LIMIT, но иногда между ними бывает разница.

Page 13: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Постоянные соединения с MySQL - зло?

Постоянные соединения с MySQL - зло?Авторы: http://mysqlperformanceblog.com, перевод: Андрей Олищук

Вы вероятно знаете, что расширение “mysql” поддерживает постоянные (persistent) соединения, но вот в “mysqli” они запрещены, что является не последней причиной, тормозящей переход разработчиков на данное расширение.

Причина использования постоянных соединений, конечно же, кроется в урезании количества подключений к базе данных, которые сами по себе довольно затратные, хотя в MySQL срабатывают быстрее чем во многих других СУБД.

Дорога не только процедура подключения. Вы запросто можете получить головную боль, устанавливая большое количество соединений. Проблема может быть в том, что большое число активных соединений между хостом «Apache» и хостом «MySQL»: порт 3306 в TCP/IP идентифицируется по паре IP-адресов и паре портов (локальный порт и удаленный порт). Т.е. если вы устанавливаете тысячи соединений в секунду то в обычных условиях работаете с ними недолго, но вот операционная система продолжает с ними работать и после вас. Согласно TCP/IP протоколу порты не могут незамедлительно быть задействованными еще раз. Должно пройти некоторое время, пока они не выйдут из стадии FIN и не смогут быть использованы вновь.

На Linux вы можете задействовать больше портов используя “/proc/sys/net/ipv4/ip_local_port_range” в целях сокращения срока задержки. Правда, сокращение срока задержки вопреки требованиям протокола в теории может привести к некоторым проблемам. По крайней мере у меня все работает.

Другой способ обойти проблему – использовать несколько IP на вашем сервере с MySQL (наверняка вы используете диапазон IP внутренней сети). Так можно избежать некоторых трудностей, однако многочисленные соединения по прежнему будут тратить ресурсы понапрасну и увеличивать время отклика сервера.

В современных Linux-системах вы можете создавать тысячи соединений с MySQL, хотя, конечно, управление большим количеством потоков будет несколько затратным. Потоки потребляют ресурсы и ядра и MySQL, но большинство проблем может случиться в случае перегрузки. В случае, если количество соединений ограничено, вы начнете получать ошибки подключения которые легко обработать. Если же разрешено большое количество соединений, то вы можете получить 4000 запросов, работающих одновременно, при этом они не высвободят свои ресурсы и пользователи будут долго ожидать ответа и жать на кнопку браузера «Обновить».

Плюс, это особенно касается InnoDB таблиц, производительность будет падать драматически – вы можете получить в сто (!) раз меньшую производительность по сравнению с тем, что было бы при всего нескольких конкурирующих запросах. А если еще запросы выполняют большие сортировки, используют временные таблицы или что-то другое, требующее ресурсов, вы можете получить нехватку памяти (“out of memory”), что приведет к падению сервера или агрессивному «прожорству» MySQL по отношению к SWAP.

Мнение: Проблема работы с постоянными соединениями состоит в том, что они абсо­лютно не нужны в хорошо спроектирован­ных веб-приложениях. Не каждый веб-запрос (если хорошо спроектирован) должен подключаться к MySQL. Кроме того, если со­единение потребуется для каждого процесса Apache, то система будет плохо масштабиру­емой и начнет доставлять головную боль спустя короткое время.

Page 14: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Постоянные соединения с MySQL - зло?

Корни проблемы с тысячами соединений в большинстве случаев растут из неправильной конфигурации или отсутствия желания оптимизировать систему на стороне веб-скрипта. Тысячи конкурирующих подключений обычно являются результатом тех случаев, когда запущено много дочерних процессов Apache. Большинство из них просто хранят состояние готовности пока соединение открыто, а остальные обслуживают статический контент вроде картинок для чего не требуется соединения с MySQL.

В оптимальной конфигурации, Apache обращается к локальной установке MySQL без удаленного доступа через сеть. В таком случае возникает 20-30 процессов. Но вы должны нагружать их постоянно, чтобы они не «болтались» в состоянии ожидания своего закрытия или не висели просто ради поддержки вывода изображений. На переднем краю вы можете поставить squid, использовать proxy модуль Apache или даже задействовать lighttpd с FastCGI для решения этих проблем.

Наконец, поговорим о том, почему постоянные соединения были заблокированы в mysqli. Даже если учитывать, что вы можете использовать их неправильно и снижать производительность своей системы, все это не повод для исключения возможности в целом. Настоящая причина – вы можете получить еще больше проблем с ними.

Постоянные соединения были добавлены в РНР во время основных версий MySQL 3.22/3.23, когда эта СУБД была довольно простой и вы могли избавляться от ненужных подключений без проблем. Но с ростом сложности СУБД, выросло и количество трудных мест – если вы закроете соединение при незакрытой транзакции, то получите большую головную боль. Если вы закроете соединение при использовании индивидуального набора знаков (character set) то снова окажетесь в трудной ситуации, не говоря уже о возможных изменениях в сессионных переменных.

Большинство приложений вполне хороши – т.е. если у вас есть страничка «только для чтения» и все на сайте используется в одной кодировке, то система будет работать хорошо, но в сложных приложениях замучаетесь отлаживать ошибки и вылавливать источники проблем.

Есть ли выход из ситуации?

MySQL поддерживает команды, которые сбрасывают соединение и гарантируют, что вновь созданное соединение будет таким же как сброшенное, так что обеспечение «постоянности» соединения будет прозрачным. Возможно, стоит даже получать ID свежего соединения и если вы работаете с веб-запросами в MySQL логах это сработает.

Итак, постоянные соединения это не зло, но они требуют внимания и доработки со стороны MySQL. Сейчас, с выходом драйвера mysqlnd для РНР, все усилия команды MySQL должны оправдаться и решить вопрос.

Мнение: Еще одна причина отказаться от постоянных соединений – если пользователь устанавливает на сер­вер несколько различных приложений и привязывает к ним разные базы, то в условиях постоянных соединений и блог и счетчик посетителей и баннерная «крутилка» с форумом создадут свои наборы соединений и каждый процесс Apache получит по 4 одновременных постоян­ных соединения. Если разрешить эту проблему (а про­стых увещеваний пользователей недостаточно) то и по­стоянные соединения станут полезными.

Page 15: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> UNION для увеличения производительности

UNION для увеличения производительностиАвторы: http://mysqlperformanceblog.com, Перевод: Андрей Олищук

В данной статье мы рассмотрим небольшой факт об индексации в MySQL. Понимание процесса работы индексов является очень важным условием для оптимизации производительности СУБД.

К примеру, если в вашей базе заведена таблица people с ключами (age, zip) и вы выполните запрос вроде этого:SELECT name FROM people WHERE age BETWEEN 18 AND 20 AND zip IN (12345,12346, 12347)

то как вы думаете, механизм индексов будет использован эффективно? В теории – да, он должен просмотреть каждый из перечисленных возрастов (age) и почтовых индексов (zip), однако на практике все обстоит по другому.mysql> EXPLAIN SELECT name FROM people WHERE age BETWEEN 18 AND 20 AND zip IN (12345,12346, 12347);+----+-------------+--------+-------+---------------+------+---------+------+-------+-------------+| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |+----+-------------+--------+-------+---------------+------+---------+------+-------+-------------+| 1 | SIMPLE | people | range | age | age | 4 | NULL | 90556 | USING WHERE |+----+-------------+--------+-------+---------------+------+---------+------+-------+-------------+1 row IN SET (0.01 sec)

Как вы можете видеть, использовалась только первая часть индекса (key_len = 4), а часть zip отработала после возвращения основных записей (обратите внимание на пометку «Using Where»). Здесь есть и другие плохие новости – все строки должны быть прочитаны целиком для нахождения zip, хотя в таких случаях нужно использовать индекс. MySQL умеет считывать индекс только для всех строк и тогда можно увидеть пометку «Using Index» в результатах запроса EXPLAIN. Если не используется индекс, то MySQL считывает данные всех строк и системой может быть задействована блокировка данных «только для чтения».

Таким образом, MySQL не всегда использует индексы, даже в тех случаях, когда это технически возможно. Для составных ключей MySQL задействует индекс только в том случае, когда для первой части выполняется операция сравнения «=». Вот пример:mysql> EXPLAIN SELECT name FROM people WHERE age=18 AND zip IN (12345,12346, 12347);+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+| id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+| 1 | SIMPLE | people | range | age | age | 4 | NULL | 3 | USING WHERE |+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+1 row IN SET (0.00 sec)

Обратите внимание на количество строк, упавшее с 90556 до 3, в то время, как значение параметра key_len осталось прежним. Такое поведение key_len, правда, выглядит как баг версии 5.0.18, которую я и использовал для этой демонстрации. В обычной ситуации параметр должен равняться 8.

Давайте посмотрим как отличается время запроса в следующих случаях:mysql> SELECT sql_no_cache name FROM people WHERE age=19 AND zip IN (12345,12346, 12347);+----------------------------------+| name |+----------------------------------+| 888ba838661aff00bbbce114a2a22423 |+----------------------------------+1 row IN SET (0.06 sec)mysql> SELECT SQL_NO_CACHE name FROM people WHERE age BETWEEN 18 AND 22 AND zip IN (12345,12346, 12347);+----------------------------------+

Page 16: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> UNION для увеличения производительности

| name |+----------------------------------+| ed4481336eb9adca222fd404fa15658e || 888ba838661aff00bbbce114a2a22423 |+----------------------------------+2 rows IN SET (1 min 56.09 sec)

Безусловно, разница огромна. К тому же, это совсем не то, что вы ожидали увидеть – ведь диапазон из пяти значений в сотни раз медленнее чем одно значение! Этой ситуации можно избежать, если в запросе использовать… UNION:mysql> SELECT name FROM people WHERE age=18 AND zip IN (12345,12346, 12347) -> UNION ALL -> SELECT name FROM people WHERE age=19 AND zip IN (12345,12346, 12347) -> UNION ALL -> SELECT name FROM people WHERE age=20 AND zip IN (12345,12346, 12347) -> UNION ALL -> SELECT name FROM people WHERE age=21 AND zip IN (12345,12346, 12347) -> UNION ALL -> SELECT name FROM people WHERE age=22 AND zip IN (12345,12346, 12347);+----------------------------------+| name |+----------------------------------+| ed4481336eb9adca222fd404fa15658e || 888ba838661aff00bbbce114a2a22423 |+----------------------------------+2 rows IN SET (0.09 sec)

Даже не смотря на то, что запрос выглядит более сложным, MySQL выполнит его гораздо быстрее, обеспечивая нам ожидаемую производительность.

Вы также можете использовать данный подход и в тех случаях, когда первой колонки из ключа вовсе нет в выражении WHERE или оно имеет несколько значений. К примеру, если заменить возраст (age) на пол, у которого существует только два значения, то использование UNION будет действительно более верным вариантом. Могу поспорить, что UNION будет быстрее даже в случае с сотней вариантов значений.

Эта стратегия может быть использована, если ничего другое уже не помогает. К примеру, если в запросах будет осуществляться поиск только по одному полю zip, то я бы посоветовал использовать ключ (zip, age) вместо обходных маневров. Обратите внимание, что на первое место я поставил колонку zip. Да, этот пример довольно надуман – в реальном мире вы можете использовать дату рождения вместо возраста и тогда подстановка колонки zip на первое место в индексе (как более легко находимого элемента) придется кстати.

Page 17: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Инженерный анализ БД MySQL с DBDesigner

Инженерный анализ БД MySQL с DBDesignerАвтор: Андрей Олищук

В задачи профессионального веб-разработчика входит не только создание новых веб-систем, но, зачастую, поддержка и развитие уже существующих приложений. Когда программист получает под свою ответственность чужой код, ему приходится исследовать еще и структуру базы данных, с которой этот код работает. Реалии таковы, что не всякое приложение бывает хорошо документированным и содержит в себе помимо комментариев «между строк» полноценную документацию для разработчиков и графическую модель базы данных. Процесс «понимания» того, как приложение работает называется инженерным анализом (англ. Reverse Engineering) и большое значение здесь играет роль исследования объектов данных, хранящихся в СУБД (Data Reverse Engineering).

Изучать, чтобы развиватьВ данной статье мы рассмотрим возможности системы проектирования баз данных DBDesigner 4 (http://fabforce.net/downloads.php), затрагивая основы инженерного анализа баз данных MySQL (хотя программа справляется и с другими СУБД). Эта система удобна тем, что позволяет не только получать графическое представление структуры существующих баз данных, но и вносить изменения в модель, синхронизируя ее с действующей БД. Другими словами, использовать DBDesigner удобно и для изучения и для развития веб-системы.

В отношении MySQL, DBDesigner получила развитие и новые версии этого ПО будут доступны на официальном сайте MySQL под наименованием MySQL Workbench (http://dev.mysql.com/downloads/gui-tools/5.0.html). Однако, на момент написания статьи, MySQL Workbench находилась еще только в стадии альфа-релиза, поэтому здесь мы рассмотрим работу с DBDesigner 4.0.5. Программа является бесплатной и работает как на платформе Windows (установочный пакет весит около 5,5 Мб), так и на платформе Linux (сжатый tar бинарных файлов, а также rpm-пакет весят по 8,7 Мб).

Так как большинство веб-разработчиков в качестве настольной ОС для работы используют Windows (хотя в большинстве случаев результаты их труда разворачиваются на серверах Linux и FreeBSD), здесь мы уделим внимание прежде всего Windows-версии DBDesigner.

Нужно сказать, что некоторый функционал по инженерному анализу присутствует и в программных пакетах по управлению базами данных, таких как MySQL Administrator или phpMyAdmin, однако, такие системы предназначены прежде всего для модификации объектов БД и не направлены на построение и публикацию экспериментальных моделей в «человеко-понятном» стиле. Целью инженерного анализа структур данных является прежде всего изучение, документирование и построение модели, а не просто возможность просмотра тех или иных полей

Андрей Олищук [nw]Независимый веб-разработчик, Главный редактор журнала «PHP Inside» и новостного блога http://phpinside.ru.

Автор более 20 технических ста­тей и соавтор книги «Разработка Web-приложений на PHP5».

Активный участник сообщества PHP-программистов http://phpclub.ru (team phpclub) и http://phpconf.ru. Для контактов с

автором используйте адрес: [email protected]

Page 18: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Инженерный анализ БД MySQL с DBDesigner

в таблице.

Идентификация существующей моделиДля того, чтобы начать изучать модель данных, ее необходимо построить путем импортирования из существующей базы данных. Здесь, под моделью данных мы будем понимать ER-диаграммы, отображающие структуру таблиц и связи между ними (если они явно существуют).

В DBDesigner импорт структуры таблиц выполняется с помощью команды Reverse Engineering (в меню: Database > Reverse Engeneering), однако, прежде чем импортировать модель базы данных, необходимо установить нужное соединение. Для этого используется менеджер соединений (в меню: Database > Connect to Database), в котором можно выбрать тип базы данных и ввести все необходимые данные для доступа к ней (рис.1). Для MySQL это традиционные: хост, имя пользователя, пароль и название базы данных.

В DBDesigner есть небольшой изъян – программа не работает с MySQL версий 4 и выше напрямую, но проблема решается использованием драйвера ODBC для MySQL и установкой подключения через ODBC. Подобный подход принесет несколько небольших проблем. Во-первых, если MyODBC драйвер не установлен в вашей Windows системе, то его придется скачать с официального сайта MySQL (http://mysql.com) и предварительно установить, проделать стандартные операции по созданию источника данных DSN. Во-вторых, при проведении процедуры импорта модели данных, программа выдаст среди пользовательских таблиц еще и целый ряд системных таблиц (их импорт можно отменить), но в целом, обе трудности не ставят непреодолимых барьеров и не затмевают ту пользу, которую может принести DBDesigner.

После установки соединения с базой данных и запуска команды Reverse Engineering, программа выдаст диалоговое окно с опциями импорта модели данных. Здесь прежде всего стоит обратить внимание на две вещи: список импортируемых таблиц (Tables) и способ выявления связей между ними (Build relations). Обычно, способом выявления связей выбирается пункт «Build Relations based on primary keys», т.е. построение связей в модели на основании первичных ключей, существующих в таблицах. Конечно, выбор данной опции не гарантирует, что система на 100% угадает все связи в модели данных.

Прежде чем нажать кнопку «Execute» («Выполнить»), не забудьте убрать галочки в списке таблиц с системных или не нужных вам пользовательских таблиц. Системные таблицы начинаются с префикса «mysql». По нажатию кнопки выполнения, на рабочем поле программы появятся все выбранные для импорта таблицы в виде ER-диаграмм (рис. 2).

Появившиеся диаграммы таблиц и связей (если удалось их определить автоматически) являются не статичными картинками, а рабочими объектами программы. Двойной клик мышью на любом из объектов приведет к открытию окна с деталями объекта. К примеру, для таблицы это будет «Table

Page 19: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Инженерный анализ БД MySQL с DBDesigner

Editor» (рис. 3). Как следует уже из названия окна, здесь можно выполнять не только подробный просмотр деталей таблицы, но вносить необходимые изменения. Важным элементом, который нам пригодится позже, является поле «Comments», появляющееся по выбору одноименного пункта из списка в левом нижнем углу редактора таблиц.

Что мы можем извлечь из представленной в редакторе таблиц информации для наших целей инженерного анализа? Прежде всего, это подробный перечень полей в таблице, их типов и дополнительных флагов (not null, auto_increment и т.д). Также, представлен список индексов для данной таблицы (внизу) и тип движка хранилища данных (MyISAM, InnoDB и т.д).

Описанный выше функционал вполне доступен и в phpMyAdmin, однако, для аналитика не всегда хватает только лишь получения модели данных. Ее нужно разделить по функциональным фрагментам и задокументировать.

Функциональная декомпозиция и документированиеФункциональная декомпозиция, т.е. разбиение модели на несколько фрагментов, относящихся к разному функционалу облегчает понимание назначения и роли каждой из таблиц. Если говорить проще, то на данном этапе мы разделяем ER-диаграммы на разные «кучи» - одни таблицы для хранения данных профилей пользователей сайта, другие таблицы для хранения информации о новостях и их категориях и т.д. Если таблицы именованы их создателем «говорящими» названиями, когда назначение понятно из названия, то задача аналитика по «сортировке» диаграмм упрощается и для анализа нет необходимости прибегать к исследованию кода, но если приложение довольно сложное или проектировщик БД назвал таблицы «непонятными» словами, то в декомпозиции поможет анализ PHP-кода (к примеру, если PHP-класс для работы с новостями использует таблицу n_tbl, то ее, скорее всего, можно причислить к новостному функционалу).

Чтобы не держать всю полученную классификацию таблиц в уме, нужно воспользоваться возможностями DBDesigner. В панели инструментов программы есть инструмент New Region, с помощью которого на рабочем поле можно рисовать регионы – разноцветные именованные подложки под диаграммы таблиц (рис. 4).

После того, как структура базы данных разложена не только в уме, но и на рабочем поле программы, можно переходить к ее документированию. Здесь, под документированием мы будем понимать не

Page 20: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Инженерный анализ БД MySQL с DBDesigner

написание справочника по БД, а составление документов со структурой БД, которые можно было бы передавать другим людям для исследований, демонстрации или обработки.

Первая возможность, которую мы упомянем – генерация структуры данных в виде HTML-документа (к примеру для быстрой публикации в сети). В DBDesigner для данной цели используется плагин «HTML Report», поставляемый вместе с программой (в меню: Plugins > HTML Report). При его использовании можно указать некоторые опции и получить HTML-документ, в котором будет учтена декомпозиция (на основе regions) и даже комментарии, которые можно указать в редакторе таблиц после их импорта в DBDesigner.

Если все выполнить тщательно, то на выходе можно получить довольно подробный документ (рис. 5), в котором ваши коллеги смогут легко увидеть список таблиц, их функциональное назначение, состав полей и индексов для каждой таблицы, а также комментарии к ней. Самое главное, что вся информация подготавливается автоматически и за короткий срок. Самый долгий по времени процесс – это умственная работа аналитика по исследованию, декомпозиции и комментированию модели, технически, все это фиксируется и конвертируется в нужный формат очень быстро.

Следующий инструмент аналитика: сохранение структуры данных в виде изображения. Выполнив команду Export model as image (В меню: File > Export > Export model as image), можно получить PNG или BMP файл с изображением всей модели данных в таком же виде, в каком вы ее видите на рабочем поле DBDesigner. Что-то вроде скриншота, который включает в себя не только зону видимости в мониторе, но всю модель данных целиком в пропорции 1:1.

Такой инструмент подойдет для быстрого обмена информацией с коллегами, когда нет необходимости предоставлять подробные данные по каждой таблице и комментарии, а достаточно основной схемы. Либо, картинку можно распечатать и использовать как «быструю» схему при анализе или доработке приложения.

DBDesigner предоставляет функционал не только для документирования «Машина – Человеку» (т.е. когда конечный документ предназначен для человека), но и для схемы «Машина – Машине». В случаях, когда схему данных будет необходимо открыть в других программах (в т.ч. для развертывания модели в рамках СУБД MS Access), можно использовать команду сохранения модели в XML Export Model As MDB XML File (в меню: File > Export > Export Model As MDB XML File).

К слову сказать, у DBDesigner есть и собственный XML формат для хранения и обмена моделями данных. Это значит, что если у вашего коллеги на машине тоже установлен DBDesigner, то можно просто передать ему «родной» для этой программы XML файл. С другой стороны, это означает и то, что модели данных для DBDesigner могут генерироваться и другими приложениями (в том числе и PHP-приложениями). К примеру, было бы неплохо, если бы тот же phpMyAdmin умел экспортировать схему БД в формат DBDesigner.

Page 21: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Инженерный анализ БД MySQL с DBDesigner

Правка и синхронизацияКак упоминалось в начале статьи, инженерный анализ базы данных зачастую проводится для последующего развития или рефакторинга (переделки) приложения. DBDesigner по своей сути является прежде всего инструментом проектирования баз данных, поэтому с дальнейшим развитием импортированной ранее модели он справляется отлично. Фактически, импортированная модель данных для программы ничем не отличается от нарисованной вами. К примеру, используя редактор таблиц, можно менять наименования таблиц, полей, менять их свойства, управлять индексами. Если планируется добавление или удаление таблиц и связей – DBDesigner поможет и здесь. В данной статье мы не будем подробно останавливаться на креаторских возможностях программы и рассмотрим еще один касающийся инженерного анализа момент – синхронизацию исправленной модели с базой-источником.

Допустим, вы импортировали модель данных, внесли в некоторые таблицы новые поля и добавили к модели еще одну новую таблицу. Чтобы новая модель «незаметно» применилась к изначальной базе данных, ее нужно синхронизировать. Условно можно сказать, что команда Database Synchronisation (в меню: Database > Database Synchronisation) является полной противоположностью ранее рассмотренной команды Reverse Engineering. Последняя импортирует схему данных в DBDesigner, в то время как синхронизация «заливает» новую схему данных из DBDesigner в базу данных. Важный момент – процедура происходит безопасно для самих данных (если конечно они остаются в новой модели). Другими словами, когда вы импортировали таблицу, добавили в нее новое поле и синхронизировали модель с БД, все данные в базе сохранятся. Просто в таблице появится новое поле со значением по-умолчанию. При синхронизации можно варьировать опции, к примеру, не удалять (или удалять) существующие в БД таблицы, если они вдруг не вошли в новую модель.

Если синхронизация напрямую невозможна или затруднительна (к примеру, необходимо к существующей базе на веб-сервере добавить таблицу из модели данных DBDesigner, а прямое подключение к удаленной MySQL невозможно), то следует использовать контекстное меню таблицы (нажатие правой кнопки мыши над диаграммой таблицы) для выбора команды Copy SQL Create. В буфер обмена копируется сгенерированная SQL-инструкция CREATE TABLE...

Контекстное меню можно использовать и для других целей. К примеру, команда Copy SQL Insert сгенерирует в буфер обмена заготовку для запроса INSERT вида:INSERT INTO pages_tbl (p_id, p_alias, p_html, p_keywords, p_desc, p_title) VALUES(

Это может быть удобно при написании PHP-кода.

ВыводыКонечно, данная статья не может претендовать на полное руководство по инженерному анализу баз данных, однако, при желании, из нее можно извлечь шаги по исследованию существующих БД и инструменты, которые при этом можно использовать.

Если хорошо освоится с DBDesigner (что, уверяю вас, несложно), то процесс анализа, документирования и правки моделей баз данных станет более простым делом. Прежде всего, будет известно с чего начать (импорт данных в вид модели из диаграмм), чем продолжить (функциональная декомпозиция и документирование) и как использовать полученные результаты (развитие модели).

Надеюсь, что полученная информация сможет вам пригодиться. Удачного инженерного анализа!

Page 22: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Не забудьте про данные!

Не забудьте про данные!Автор: Brian K. Jones, перевод: Владимир Захват

Если у вас есть аккаунт на sourceforge с приложением, которое, по вашему мнению, призвано стать лучшим в интернете со времен Yahoo и Google, то я с чистой совестью причислю вас к людям, знающим толк в проектировании баз данных.

Проектирование интерфейса для PHP-приложения – это одно, а вот проектирование самого приложения – это совсем другое дело, так как процесс включает в себя планирование таких вещей как взаимодействие компонентов между собой и управление данными, а так же способами их хранения. Работа с данными почему-то зачастую принимается за какую-то банальную и непривлекательную часть программинга, хотя на самом деле имеет огромное значение.

Если вы являетесь PHP-программистом, то я отнюдь не буду учить вас проектировать базы данных. Я просто подскажу вам, как писать PHP-код. В природе существует небольшое количество людей, которые с обеими задачами справляются «на ура», так как и проектирование и написание кода требует немалого времени. В любом случае, путь к мастерству всегда лежит через осознание того факта, что вы чего-то еще не умеете. Вот и сейчас, представьте, что вы никогда не изучали науку проектирования баз данных, поэтому ищете подсказок и советов.

Очень странно, но в разделе sourceforge «Help wanted», где администраторы проектов размещают объявления о вакансиях в их проектах, я никогда не встречал запросы на дизайнеров баз данных. Я искал. Время от времени я заходил на сайт снова и снова, однако поиски не увенчивались успехом, и я разочаровывался. Тем временем, в списке проектов было огромное количество приложений, использующих СУБД и многие из тех, которые я изучал – оставляли неприятный осадок.

По моему мнению, большинство проблем в этой сфере возникли по причине перечисленных ниже заблуждений.

Заблуждение 1. Интерфейс определяет структуру данныхПозвольте не согласиться. Такой подход я считаю слишком близоруким. Если ему следовать, то в какой-то момент мы придем к необходимости менять структуру данных при изменении внешнего вида приложения. Это вызовет проблемы по затрате огромного количества рабочего времени и приведет к несовместимости новой версии продукта с предыдущими релизами.

Более того, вы окажетесь у разбитого корыта, если на одни данные придется разрабатывать несколько различных приложений. И что тогда? Какой интерфейс будет главным?

На самом деле, схема данных и интерфейс должны быть связаны через сами элементы данных. Модель данных – это определение взаимосвязей между данными и интерфейс должен определять только то, как эти связи отобразить для пользователя. Исходя из этого, сделаем вывод, что схема

Брайан ДжонсСистемный администратор/Админи­стратор баз данных в департаменте компьютерных наук Принстонского Университета.

Является автором статей, опублико­ванных на сайтах: http://www.oreillynet.com, http://linux.com и многих других. Основатель проекта http://www.linuxlaboratory.org/.

Адрес для связи с автором: [email protected]

Page 23: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> В фокусе >> Не забудьте про данные!

данных не должна зависеть от интерфейса.

Заблуждение 2. «Мне нужна простенькая структура БД»Возможно это и так, однако подумайте дважды, перед тем как начать делать. Если вы создадите приложение даже на основе трех таблиц, но при этом «навертите» кучу-малу из дублирующихся данных, пустых ненужных полей или, что еще хуже, из полей содержащих не одно значение, то вы получите плохо расширяемое приложение. В будущем, когда придет время развивать проект, вы придете к необходимости «переделать все заново», что является ужасом для любого разработчика. В большинстве проектов, которые я исследовал, вся оптимизация базы данных сводилась к максимальному уменьшению количества таблиц, однако ни о какой нормализации не шло и речи. Более того, в реальном мире, нормализация наоборот приводит к увеличению количества таблиц. Отсюда вытекает:

Заблуждение 3. «Много таблиц бывает только в сложных проектах»Уменьшение количества таблиц за счет пренебрежения нормализацией рано или поздно приводит к рефакторингу и переписыванию приложения, так как оно может не справляться с новыми требованиями. Разрабатывая ненормализованное приложение, заранее приготовьте кирку для будущих работ.

В большинстве случаев, работа с нормализованными схемами данных усложняется не очень сильно. Конечно, запросы на вставку данных станут немного сложнее, а для выборки (SELECT) вы всегда сможете использовать упрощающие работу Представления (VIEW). Если ваша СУБД их поддерживает, а вы не знаете как ими пользоваться – спросите совета у профессионалов.

ЗаключениеЯ не являюсь ревностным сторонником пятой формы нормализации для всех и вся. На самом деле, я уже давно работаю в сфере консалтинга по базам данных, но не так часто слышал о реально применяемой пятой форме. Я бы сказал, что уже и третей нормальной формы хватает большинству приложений для сохранения их гибкости в последующем развитии и при этом, вашим PHP-программистам не нужно будет становиться черными магами SQL-кода. Проектирование баз данных – это сухая, монотонная и, может быть, даже мазохистская работа. Но эта работа, будучи выполненной качественно, принесет свои дивиденды в будущем.

Page 24: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Введение в сокеты

Введение в сокетыАвтор: Jim Plush, перевод: Владимир Захват

Данное руководство рассчитано на повышение вашего мастерства и на разрешение проблемных вопросов, которые могут возникнуть при изучении программирования сокетов на PHP.

Для начала, давайте разберемся с тем, что собой представляют сокеты. Посмотрите на изображение ниже – вполне приемлемо представлять такие муфты (в англ. языке муфта так же называется socket), говоря о сокетах в PHP-программировании. Концептуально, между муфтой и сокетом нет особой разницы. Сокет предназначается для подключения одного компьютера к другому. Компьютер может находиться как в соседней комнате, так и на другом конце света и такое программирование называется сетевым.

Вашему компьютеру присваивается IP-адрес, благодаря которому, любой другой компьютер в мире знает, как вас найти, чтобы подключиться (давайте представим себе мир без файерволов). Такие «сторонние» компьютеры взаимодействуют с вашей машиной посредством портов. Это позволяет 65000 (и более) различных приложений взаимодействовать с сетью в отдельный промежуток времени. Без портов, компьютер не смог бы разобраться, какие данные принадлежат каким приложениям.

Наиболее близкий нам пример работы портов – всемирная паутина. Чаще всего, www трафик передается через порт 80. Когда вы отправляете запрос к веб-страничке, ваш браузер открывает сокетное соединение с восьмидесятым портом на сервере и говорит «эй, дай мне вот эту страничку». В тоже время, запрашиваемый веб-сервер постоянно «слушает» восьмидесятый порт в ожидании таких вот запросов. Запрос по восьмидесятому порту может выглядеть следующим образом: "GET /index.html HTTP/1.0\r\n". В данном случае, веб-клиент (браузер) говорит: «Я хочу получить страничку index.html, предоставьте!».

Другой пример – работа FTP, которая обычно осуществляется по 21 порту. Есть множество приложений, использующих порты для обмена данными через сеть. В этом окружении обитают и вирусы с троянами. Они поддерживают сокеты открытыми для внешнего мира, дожидаются поступления внешней команды на эти порты и начинают воровать данные с вашей машины, либо атакуют соседние компьютеры. Уже умнеете? Вы можете в любой момент проверить список открытых портов, напечатав «netstat» в командной строке любой из популярных ОС. При этом вы сможете увидеть список подключенных к вашему компьютеру машин и номера используемых ими портов.

Сокеты и PHPВ PHP работать с сокетами довольно просто. Вы можете решать множество сложных задач, используя этот язык. Для примера можно привести небольшой сокетный сервер, к которому смогут одновременно подключаться несколько приложений. Каждое такое приложение будет стараться передавать какую либо информацию системе, а уже система будет ее распределять. Другими словами, клиенты, написанные на С++, будут подключаться к сокет-серверу, а он будет принимать данные от одних клиентов и передавать ее другим. На PHP эта задача решается вполне легко.

Итак, приступим к написанию сервера. Концепция проста: вы создаете программу, которая постоянно висит в памяти и говорит «Подключайтесь ко мне! Я тут, на порту 10000!». Создание сокета в некотором роде напоминает использование телефона. Для того, чтобы совершить

Page 25: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Введение в сокеты

телефонный звонок, нужно пройти некоторые шаги, не так ли? Давайте, сопоставим наши шаги (функции для работы с сокетами) с телефонным звонком:

1. Принести телефон и поставить на тумбочку – socket_create().

2. Включить телефон в телефонную розетку – socket_bind().

3. Включить питание телефона (имеется в виду power on для современных аппаратов) – socket_listen().

4. Когда телефон зазвонит, взять трубку и говорить – socket_accept().

TCP & UDP протоколыВ большинстве случаев вы будете использовать сокеты посредством протоколов TCP или UDP. В чем разница, спросите вы? При передаче через TCP, если я отправляю вам данные «1,2,3», это значит, что вы получите «1,2,3». Это тоже напоминает телефонный разговор. Когда я беру трубку, я слышу вас на другом конце провода. Я могу слушать ваши слова и говорить с вами, а самое главное – буду знать, когда вы положите трубку. UDP не соответствует этой концепции. Сокеты при UDP больше напоминают голосовую почту. Вы звоните, оставляете свое сообщение, но не имеете понятия, будет ли оно прослушано.

Всемирная паутина основана на протоколе TCP. Вы хотите всегда быть уверенными, что получаете всю страницу, а не ее часть. Для UDP протокола все обстоит иначе. Передача потоковых данных (музыки к примеру) очень подходит такому протоколу. Если вы слушаете песню, в то время как она миллионами мелких пакетов передается к вам на компьютер, то захотите ли ее прослушать с самого начала, если вдруг один из пакетов потеряется? «Бог с этим пакетом, я даже не заметил его потери!» - скажете вы, и будете слушать песню дальше.

PHP Socket ServerДавайте начнем с первого шага и посмотрим, как PHP-команды и их опции влияют на наш сервер. Первая задача: создать сервер, слушающий порт 10000, принимающий сообщения и отправляющий текстовое сообщение подключенному клиенту. Начнем с простого, и будем повышать сложность материала постепенно.

Шаг 1

Когда мы сравнивали сокеты в PHP с использованием телефона, то первым шагом было поставить телефон на тумбочку – socket_create(). Данная функция создает ресурс в операционной системе, который мы и будем далее использовать. В итоге получаем дескриптор, вроде того, что создается при работе с обычными файлами в коде $fp = fopen("myfile.txt", "r"). Переменная $fp теперь содержит «ресурс», который можно передавать в другие функции для взаимодействия с ним. Таким образом, операционная система говорит нам: «Вот вам способ работы с моими ресурсами». Посмотрим на функцию подробнее:socket_create()resource socket_create ( int domain, int type, int protocol )

Как вы можете увидеть выше, когда мы вызываем данную функцию, то передаем ей три обязательных параметра.

Page 26: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Введение в сокеты

Типичный вызов функции может выглядеть вот так:$mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

Рассмотрим этот вызов поподробнее. Первый параметр - AF_INET. AF = Address Family и INET обычно означает «Internet». Т.е. так указывается семья адресов. Этот параметр будет таким в 99,9% ваших задач. Это позволяет использовать TCP или UDP для связи с компьютерами. Вместо этого значения вы можете указать и AF_UNIX, которое позволит оперировать с внутренними процессами, работающими в Unix. На первый раз просто запомните параметр AF_INET и используйте его.

Второй параметр - SOCK_STREAM является константой, указывающей на то, что необходимо установить соединение по сокетному слою TCP. Для соединения по UDP используйте в качестве параметра SOCK_DGRAM. Или ставьте SOCK_RAW для транспортировки данных по вашему собственному слою. Многие игровые компании используют этот подход для ускорения соединения UDP, но при этом прибегают к уведомлениям, как в TCP, создавая вот такой гибрид TCP/UDP. Правда, здесь уже попахивает обмороком, поэтому предлагаю использовать для наших примеров привычный нам TCP.

Третий пример – это SOL_TCP. Он указывает на то, что после создания соединения, мы будем и далее использовать сокетный слой (SOL – SOcket Layer) TCP.

Шаг 2

Следующий шаг – подключение телефона к телефонной розетке socket_bind(). Эта функция привязывает выделенный операционной системой ресурс к конкретному порту.

Если в первом шаге мы говорили операционной системе: «Дай нам кабель для передачи данных», то теперь говорим: «Кабель получен, теперь подключай его к порту 10000 чтобы я начал разговаривать с людьми». В socket_bind() мы привязываем наше приложение к определенному порту . Это звучит примерно как: «Эй, парень, если кто захочет поговорить с портом 10000, направляй ко мне».socket_bind($mysock, "127.0.0.1", 10000));

Первый параметр – это дескриптор ресурса, полученный при создании сокета в первом шаге. Второй параметр – IP адрес, под именем которого мы хотим получать данные. В этом случае используем локальный 127.0.0.1. Наконец, последний параметр и есть номер порта. С этого момента мы «встроены» в систему.

Шаг 3

Вот мы и создали сокет, привязали его к операционной системе на порт 10000 и теперь должны включить электропитание, чтобы сокет ожил и начал ожидать звонки. Для этого используем функцию socket_listen(). Эта функция сообщает операционной системе, что вы проделали большую работу по созданию сокета и теперь хотите принимать по нему «звонки». Второй параметр функции указывает на то, сколько соединений вы будете «удерживать на линии», пока заняты другим соединением.

Это похоже на ситуацию, когда вы звоните в большую компанию и там для вас играет музыка, и женский голос говорит «не кладите, пожалуйста, трубку, ваш звонок очень важен для нас». Их система ставит вас в очередь, и звонок отражается на аппарате мигающей лампочкой. Если же очередь на соединение слишком велика, то вы просто не сможете дозвониться. Вот так и сокет начнет сбрасывать соединения, когда количество подключенных клиентов достигнет указанного максимума.

Page 27: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Введение в сокеты

socket_listen($mysock, 5);

Как вы можете видеть, мы снова указали дескриптор ресурса в качестве первого параметра. Цифра 5 означает следующее: «Сейчас я говорю с кем-то, но пять человек могут оставаться на линии».

Собираем все вместе

Давайте расширим наш пример и создадим простейший сокетный сервер. В данном примере мы не будем писать обработчики ошибок и оставим их для следующей задачи.#!/usr/bin/php -q

<?php

$address = "10.139.17.143";

$port = "10000";

/* создать сокет семейства AF_INET используя SOCK_STREAM для TCP соединения */

$mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

socket_bind($mysock, $address, $port);

socket_listen($mysock, 5);

$client = socket_accept($mysock);

// читаем ввод пользователя на 1024 байт

$input = socket_read($client, 1024);

$output = "thanks for connecting, you wrote: ".$input."\r\n";

// Возвращаем ответ

socket_write($client, $output);

socket_close($client);

Page 28: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Введение в сокеты

socket_close($mysock);

?>

Давайте взглянем на новые строки кода. Первая строка указывает на нахождение исполняемого файла PHP. Так как мы не используем веб-сервер, то операционная система (Unix в данном случае) должна знать путь к PHP (в Windows можно написать bat-файл с запуском php.exe и указанием пути к файлу нашего скрипта-сервера – прим. переводчика).

Укажите путь к PHP в вашей системе. Далее мы создаем сокет, привязываем его к порту и запускаем его на «прослушку» этого порта. Как только поступает соединение, мы принимаем его функцией socket_accept(). Т.е. присваиваем соединению имя $client = socket_accept($mysock), что позволяет нам в дальнейшем оперировать с конкретным подключенным пользователем через переменную $client. Все что клиент отправляет нам, записываем в переменную $input, точнее не все, а 1024 первых байта его сообщения. Когда входные данные получены, переходим к передаче нашего сообщения. Затем мы закрываем сокет и программа завершается. Такой сервер обслуживает одного клиента и затем умирает – не очень полезно, но зато мы создали свой первый сервер.

Давайте попробуем запустить наш сервер и подключиться к нему. Откроем командную строку, и запустим скрипт сервера на выполнение. К примеру, если вы сохранили файл как app_server.php, то смените права на 777 и запустите его. Теперь в другом экземпляре (окне) командной строки наберите команду: telnet 127.0.0.1 10000.

Данная команда откроет сессию соединения с локальной машиной по порту 10000. Таким образом, вы попытаетесь подключиться к вашему серверу как клиент. Если все пойдет хорошо, то напишите пару слов и нажмите Enter. Сервер повторит все, что вы написали.

Page 29: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Как выбирать хостинг?

Как выбирать хостинг?Автор: Gary Sims, перевод Сергей Борзов

Выбор хостинга – это очень важный процесс. Выбирая провайдера услуг на основе рекламных объявлений, вы можете получить большую головную боль, которой можно избежать, если будете знать, что искать.

Первая вещь, которую необходимо решить заранее – это тип нужного вам хостинга. Обычно, хостинг на базе Linux делится на три основных категории: виртуальный хостинг (shared hosting), виртуальные частные серверы (VPS) и выделенные серверы (dedicated servers). Если говорить поверхностно, то виртуальный хостинг подходит для личных нужд и сайтов компаний малого бизнеса, VPS будет интересен проектам среднего уровня, а выделенные серверы больше подходят для надежной работы больших проектов корпоративного уровня.

При использовании виртуального хостинга, ваш сайт располагается на сервере не один, а среди других сайтов. При этом вы имеете минимальный контроль (или не имеете вообще) над самим сервером, и осуществляете полный контроль над своим сайтом (обычно, через контрольную панель). Этот вид хостинга наиболее дешев и прост в обслуживании, с точки зрения администратора сайта. В большинстве случаев, владельцы хостинга предложат вам предустановленное программное обеспечение LAMP (Linux, Apache, MySQL и PHP) в комплекте услуг. Стоимость такого хостинга обычно варьируется от двух до тридцати долларов в месяц, в зависимости от выбранных вами опций.

Технология VPS более продвинута и делит один физический сервер на несколько отдельных виртуальных серверов. Каждый из таких виртуальных серверов представляет собой как бы отдельную физическую машину. Администратор может входить в систему и управлять ею по своему усмотрению, включая возможности запуска и остановки процессов и конфигурирования приложений. При необходимости, виртуальную машину можно даже перезагрузить, не влияя на остальные виртуальные серверы, размещенные на этой же физической машине. Каждая виртуальная машина имеет собственное количество реальных ресурсов памяти и процессорной мощности. Такой хостинг обычно стоит от 15$ и до $100, опять же, в зависимости от выбранных опций.

И, наконец, выделенный сервер представляет собой отдельную физическую машину, которую вы арендуете у хостинговой компании. Все ресурсы этой машины принадлежат только вам и вашему сайту (сайтам). Выделенные серверы обычно стоят от $70 и до $300 в месяц, в зависимости от мощности процессора, количества памяти и вместимости жесткого диска арендуемой машины.

Что же вы можете получить за свои деньги? Какой функционал будет доступен, и как вы определите, что именно он вам нужен? Давайте взглянем на две основные опции хостинга: дисковое пространство и ограничение трафика.

Каждый веб-сайт, даже самый маленький, требует пространства на жестком диске. Минимально можно найти лимиты на 50 Мб – 100 Мб, а максимальный размер пространства предоставляется в выделенных серверах и обычно зависит от вместимости жесткого диска. Таким образом, этот показатель достигает несколько сотен гигабайт. Сколько же вам будет нужно? Есть некоторые

Гари Симс

Получил высшее образование в Британском Университете по направлению информацион­ных систем в бизнесе. На протяжении 10 лет работал инженером по разработке программ­ного обеспечения, а теперь занимается незави­симыми проектами как консультант и разработ­чик в сфере ОС Linux.

Page 30: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Как выбирать хостинг?

рекомендации.

Обычный пятистраничный сайт с небольшим объемом графики поместится в 400 Кб, что составляет менее одного процента от 50 Мб. Вы можете взять за основу 80 Кб и умножить это число на количество страниц вашего сайта. Таким образом, вы и получите необходимое пространство. С другой стороны, динамические сайты с бэк-эндом и базой данных, потребуют больше места. Документ на полторы тысячи слов в среднем занимает 9 Кб в базе данных, поэтому, сайт из тысячи документов, потребует уже около 9 Мб дискового пространства. Если при этом вы храните к каждому из документов еще и графические файлы, программы для скачивания или медиа-файлы, то требования возрастут ровно на их объем. Один из сайтов, который мне приходилось администрировать, содержал 4 Гб звуковых файлов с речами из различных конференций, но другой мой сайт умещался всего в 5 Мб. В хостинге, чем вы больше платите, тем большее количество места на диске получаете в результате.

Второй важный фактор при выборе хостинга – ограничение трафика. Каждый раз, как кто-нибудь открывает в браузере страничку вашего сайта, используется пропускная способность каналов вашего провайдера. Обычно, хостинговые компании ограничивают размер пропускной способности для каждого клиента. Здесь, как и с дисковым пространством – чем больше вы платите, тем большую пропускную способность можете получить. Если у сайта в день бывает 50 посетителей и каждый из них скачивает (просматривает) по 10 страниц, то в итоге, сайт создаст трафик в 40 Мб (исходя из веса одной странички в 80 Кб). В месяц этот показатель составит примерно 1 Гб. В случае, когда сайт имеет еще большую популярность и посетители не просто просматривают странички, но и качают программы и медиа-файлы, то лимит пропускной способности должен быть еще выше.

Помимо дискового пространства и ограничения трафика, существуют и менее значимые опции, о которых следует знать. Первый пример – количество почтовых ящиков, доступных для создания. В виртуальном хостинге предоставляется от 1 до 50 уникальных почтовых ящиков и один ящик по-умолчанию, в который будет доставляться вся почта, пришедшая на другие адреса вашего сайта. Для VPS и выделенных серверов таких ограничений обычно не бывает.

Еще одна опция – количество возможных баз данных MySQL. Простые тарифные планы могут вообще не предполагать наличия MySQL или давать доступ к одной базе. Конечно же, в обычных случаях одной базы вполне хватит, но существуют причины, по которым вам потребуется сразу несколько баз. К примеру, вы захотите использовать несколько приложений с одинаковыми именами таблиц. Большинство современного ПО позволяет устанавливать префиксы к таблицам, допуская использование разных приложений в рамках одной базы данных, однако конфликты могут случаться. С другой стороны, вам может потребоваться тестовая база данных, на которой вы будете обкатывать все новинки перед выкладкой их на основном ресурсе. Для VDS, как и для выделенных серверов, количество БД обычно не ограничивается.

Еще один небольшой фактор – количество субдоменов, которые можно будет создать. Зачастую их количество не ограничивается, однако дешевые планы могут как ограничивать такую услугу, так и не предоставлять ее вовсе.

Необходимо обратить внимание и на то, существует ли возможность создания нескольких сайтов на одном аккаунте, и как много FTP-аккаунтов вы сможете создать.

Когда планируете покупку хостинга для среднего ресурса или проекта корпоративного уровня, вам необходимо предусмотреть возможности роста проекта в будущем. По мере увеличения присутствия вашей компании в сети, потребуются ресурсы для введения и новых сервисов на сайте. Для такой ситуации лучшим решением является выделенный сервер, так как его ресурсы находятся под вашим полным контролем. К тому же, здесь вы сможете добавлять и дополнительные серверы, используя механизмы распределения нагрузки (т.н. Load Balancer).

Page 31: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> newbie >> Как выбирать хостинг?

Всегда выбирайте проверенных провайдеров, с хорошей технической поддержкой и высоким показателем аптайма (фактической доступности сервера). Спросите предполагаемого провайдера о времени работы его техподдержки – это только рабочее время или режим круглосуточной поддержки семь дней в неделю? Уточните, будут ли возвращены деньги в случае отказа серверов. Вы можете так же исследовать и другие сервисы, которые предоставляет провайдер, например автоматическое резервное копирование, распределение нагрузки и SSL сертификаты.

Оригинал статьи можно найти по адресу: http://www.itmanagersjournal.com/article.pl?sid=05/11/16/1717203

Page 32: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Люди >> Интервью с Andrei Zmievski

Интервью с Andrei ZmievskiАндрей, так как вы владеете темой, давайте поговорим о юникоде в PHP 6. Почему юникод так важен для PHP?

На самом деле юникод должен был появиться в РНР пять лет назад. Очень плохо, что никто в то время не предпринимал усилий и даже не изъявлял никакого желания сесть и реализовать поддержку юникода. Это сэкономило бы массу сил тем разработчикам, которые создают свои приложения в условиях неанглийских локалей и работают с интернациональными интерфейсами. Теперь мы сталкиваемся со множеством проблем, ведь с тех пор написано немало нового кода. Например - mbstring, от которого нам теперь придется избавляться.

Реальной причиной, по которой мы вводим поддержку юникода в РНР 6 является то, что каждый высокоуровневый язык программирования ориентированный на веб должен ее иметь. Причины вполне очевидны: обработка национальных текстов, одновременная работа с текстами на разных языках, все это очень важные инструменты. Чтобы быть реально полезными, они должны быть встроены на уровне языка. Импульсом для начала работ в этом направлении стало то, что Yahoo работает со многими мультиязычными сервисами и мы, как разработчики прошли через много трудностей и обходных путей чтобы выполнить свою задачу. С такими же трудностями сталкивались и другие разработчики, пытаясь создавать разрозненные библиотеки. Введение поддержки юникода на уровне языка сделает все вещи более простыми.

Со своей стороны, я написал предложение своему руководству в Yahoo, чтобы оно позволило мне в рабочее время писать весь необходимый код и передавать его сообществу. Вот так все началось.

Спасибо за введение в курс дела. Теперь давайте поговорим о самом проекте. Первый вопрос который возникает – как продвигается работа?

Работа продвигается хорошо. В начале года была небольшая задержка, так как в Yahoo меня временно отвлекли на решение других задач, но в оставшиеся несколько месяцев усилия наконец дадут результат. Мы движемся вперед в хорошем темпе.

Моя цель – создать предварительный релиз РНР 6 с поддержкой юникода в четвертом квартале 2006 года. Если все произойдет в середине квартала – будет здорово. Сложность состоит еще и во множестве расширений, которые должны быть портированы для поддержки юникода. Как только подготовим эти расширения и сам язык, то выпустим пререлиз РНР 6. Это даст людям возможность «поиграться» с ним и сообщить о своих замечаниях. Это не будет бетой или альфой – это будет просто предварительный релиз.

Отлично, я знаю что все разработчики ждут нового релиза чтобы протестировать его. Когда вы работаете над реализацией юникода в РНР, что является самой большой помехой?

Андрей Змиевский (Andrei Zmievski)

Сотрудник компании «Yahoo!» (подразде­ление Core Software Infrastructure), актив­ный разработчик PHP, участник многих международных конференций, в том чис­ле PHPConf 2006 в Москве, автор проекта PHP-GTK, участник Apache Software Foundation.

В разработке РНР 6 отвечает за поддерж­ку юникода на уровне ядра.

За более подробной информацией об­ращайтесь на персональную страничку

(блог) Андрея по адресу: http://www.gravitonic.com

Page 33: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Люди >> Интервью с Andrei Zmievski

В действительности, интернационализация это не совсем технология, как могло бы показаться. Ты вынужден обучаться сам и обучать других, чтобы прийти к правильному пониманию реализации. Ты должен отбросить множество предубеждений вроде «если мы делали так всегда, то почему не сделать сейчас?». Много трений возникает в обсуждениях как это должно выглядеть в конечной реализации, но сейчас люди начинают понимать, что это многонациональный мир, а не одна страна и стараются мыслить по новому.

Как много еще осталось сделать?

Как только будут обработаны ядро РНР и Zend Engine, я смогу сказать, что сделано 90-95%. Главная задача на текущий момент, конвертировать расширения. Сейчас уже преобразован XMLReader и люди работают над другими расширениями. Мы также проходимся по списку стандартных функций РНР и обновляем их при необходимости. Основную работу выполняю я, но надеюсь, что присоединятся и другие разработчики.

Другая часть дела – документация. Некоторые функции могут немного изменить свое поведение после внедрения поддержки юникода. Это должно быть задокументировано и объяснено в официальном руководстве. Придется добавить введение в юникод и рассмотреть как многие вещи будут работать в РНР 6. Сейчас этого еще не сделано, но я надеюсь на скорое движение в сторону документирования.

Поговорим о твоей работе в Yahoo, если это не секрет. Можешь рассказать о проектах, над которыми там приходится работать?

В Yahoo, помимо PHP я работаю с другими разработчиками над созданием специальных патчей для Apache 1.3 и 2.0. Мы адаптируем веб-сервер к потребностям Yahoo.

Я знаю, что в Yahoo в основном используют РНР 4. В ваших планах есть переход на пятую версию?

Множество проектов уже переносится на РНР 5. Я не могу назвать конкретную цифру, но в целом мы мигрируем на новую версию.

Хорошо. Обратим внимание на будущее. Глядя дальше РНР 6, каким ты видишь будущее РНР?

Вы же понимаете, если бы я так много знал, то уже давно бы заработал на бирже достаточно денег. Главная особенность РНР состоит в том, что он хорошо адаптируется под новые технологии. Он является соединителем между возникающими технологиями и вебом. Я уверен, что появление новинок в следующие несколько лет будет легко переварено в РНР.

Правда юникод – это довольно давно живущая технология. По сравнению с Ajax, юникоду уже исполнилось 10 или даже 15 лет, но мы прежде всего работаем над внедрением давно существующей технологии вместо вновь появившейся, так как она очень важна. Относительно РНР 7 могу сказать, что это будет не что иное как то «чего хотят пользователи». До сих пор развитие РНР шло в русле требований, возникающих со стороны пользователей.

Существует ли что-то, что разработчики РНР упустили?

С точки зрения языка программирования, есть вещи, которые хотелось бы добавить. С точки зрения веб-технологии – в РНР все отлично.

Очевидно, что нанимая Расмуса, Сару Големан, Джереми Джонстона и других активных контрибьюторов РНР, компания Yahoо сделала ставку на РНР, как на свою связующую

Page 34: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Люди >> Интервью с Andrei Zmievski

технологию. Почему?

Вам нужно посмотреть презентацию Майкла Редуина (http://www.radwin.org/michael/blog/2005/10/php_at_yahoo_presentation_.html), посвященную этой теме. В общих чертах, Yahoo использовало много внешних технологий для разработки своих фронт-эндов или сайтов. Каждая технология требует инвестиций в поддержку, обучение, разработку инструментов, тестирование и т.д. В конце концов вся система становится довольно хрупкой и мы начинаем искать ей замену и хотим нанять уже обученных специалистов. Соответственно, мы хотим получить уже хорошо поддерживаемую технологию, чтобы в будущем Yahoo не приходилось нанимать специалистов для ее эксклюзивной поддержки. Ну и наконец, мы хотим использовать технологию, которая доказала свои возможности на деле. Всему этому соответствует РНР.

Если вернуться немного в прошлое, каким образом ты пришел в РНР сообщество?

Я начал работать с РНР в маленькой веб-девелоперской компании, разрабатывающей онлайновые издательские системы. Сначала мы использовали проприетарный язык и СУБД, но перешли на РНР по тем же причинам, что и Yahoo – нам был нужен более поддерживаемый язык с большей функциональностью.

В то время существовали Apache и PHP 2/FI. Нам эта версия понравилась, но применить ее мы смогли только полгода спустя, когда появился РНР 3. Там были введены серьезные улучшения и мы начали изучать новую версию. Как только стартовала миграция на РНР, я сразу обратил внимание на недостающие в РНР элементы. После этого немного изучил АРI и начал писать необходимые вещи сам. Сначала я работал независимо, но потом подписался на лист рассылки и увидел, что другие разработчики присылают патчи, поэтому решил слать и свои наработки. Все началось с расширения WDDX, но потом я втягивался больше и больше.

Резюмируя, давай взглянем на технологии в общем. Какие новые разработки тебя удивляли в последнее время?

Мои любимые технологии связаны с компьютерной лингвистикой и процессингом естественных языков. Область их применения широка – от поисковых движков до обработки запросов и вывода данных. Я полагаю, что данная проблематика будет актуальной в ближайшие годы.

Наконец, какой сайт или блог ты читаешь каждый день?

Planet-php.org очень классный аггрегатор блогов. Также я очень интересуюсь фотографированием. В этой области есть классный сайт «The Daily Dose of Imagery» («Ежедневная порция образов») на котором фотографы ежедневно постят свои творения. Он мне очень нравится.

Page 35: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Люди >> Интервью: Chris Shiflett

Интервью: Chris Shiflett Интервьюировал: Keith Casey, перевод: Андрей Олищук

На этот раз мы предлагаем вашему вниманию интервью с автором книги «Essential PHP Security» («Основы безопасности в PHP») Крисом Шифлеттом (Chris Shiflett).

Безопасность является такой штукой, которую разработчики чаще всего «прикручивают» к приложению, когда оно уже написано. Какой подход к безопасности является самым правильным?

Безопасность ничем не отличается от таких абстрактных вещей как производительность, легкость в сопровождении и надежность. Ни одна из этих характеристик не может быть легко добавлена в уже существующее приложение. Они должны учитываться на каждой стадии разработки. Это то же самое, что попытка добавить мудрости ребенку.

Абстрактные понятия сложно измерить. Мерой безопасности приложения служит возможность предсказать и предупредить проблемы перед тем, как они будут использованы в качестве уязвимостей. Это постоянный процесс, который начинается на стадии планирования архитектуры приложения.

Ваша книга, как ясно из ее названия, сфокусирована на PHP. Есть ли в этом языке какие либо слабые или сильные стороны в этом плане, сравнительно с другими языками?

PHP дает вам достаточно шансов для самоспасения. Этот язык не только чрезвычайно гибок, но и легок в изучении – а это довольно опасная комбинация. Говоря другими словами, безопасность – это больше характеристика разработчика, а не языка программирования. Основные типы уязвимостей в веб-приложениях редко зависят от какой либо конкретной платформы. В моей книге я продемонстрировал, как можно разрабатывать безопасные PHP-приложения, но затронутые темы вполне актуальны и для других веб-платформ.

Когда вы осуществляете аудит на предмет безопасности, что исслежуете в первую очередь?

Прежде всего я изучаю назначение приложения, анализирую его архитектуру и организацию. Главная цель данного процесса – лучшее понимание приложения, так как все они разные. Если взялся изучать исходный код, то прежде всего обращаю внимание на проблемы фильтрации входящих данных и экранирования исходящих. Для этого я использую два перекрывающих друг друга подхода:

1. Определить входящие данные и пошагово оттрассировать их.

2. Определить исходящие данные и оттрассировать их в обратном направлении, чтобы проверить способы их формирования.

Крис Шифтлетт (Chris Shiflett)Является основателем и Президентом компании «Brain Bulb», которая зани­мается PHP-консалтингом и предлага­ет множество услуг по всему миру. Крис активный участник PHP-сообще­ства и его участие включает проект PHP Security Consortium, основателем которого он является, PHPCommunity.org, членство в Zend PHP Advisory Board, соавторство сер­тификационной программы Zend PHP Certification. Плодовитый автор, Крис

ведет постоянные колонки в PHP Magazine и php|architect. Он яв­ляется автором книг HTTP Developer's Handbook (Sams) и упомя­нутую в данном интервью Essential PHP Security (O'Reilly).

Page 36: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Люди >> Интервью: Chris Shiflett

В результате этих шагов я формирую три диаграммы, которые позволяют мне эффективно отслеживать логику программы и перемещение данных внутри приложения.

Если бы веб-разработчики могли сделать только что-то одно для усиления безопасности своего приложения, что бы вы порекомендовали сделать?

Экранировать выходные данные. Я рад отметить, что среди разработчиков все чаще можно наблюдать серьезное отношение к фильтрации пользовательского ввода (хотя внимание должно уделяться всем без исключения входным данным), но большинство уязвимостей являются результатом проблем с экранированием выходных данных.

К примеру, двумя самыми распространенными проблемами в этой связи являются кросс-сайтовый скриптинг (XSS) и SQL-инъекции. Все это – результат отправки непроверенных данных веб-клиенту или в базу данных. Так как в описанных случаях открывается возможность выполнять код из удаленных источников, могут произойти неприятные сюрпризы.

С появлением AJAX изменилось ли что-нибудь с точки зрения безопасности? Готовы ли разработчики к этой технологии?

AJAX влияет на безопасность двумя путями.

1. В нем есть потенциал для создания новых уязвимостей. К примеру, разработчик не всегда может правильным образом контролировать доступ со стороны AJAX-запросов. К тому же, разработчики, мало разбирающиеся даже в основах HTTP, могут допустить ошибки при добавлении функционала AJAX в приложение.

2. В нем есть потенциал оживить ранее существовавшие уязвимости. На протяжение последних нескольких лет, мы могли наблюдать рост количества случаев кросс-сайтового скриптинга (XSS), так как клиентские технологии становятся все более хитрыми. Популярность AJAX увеличит количество злоумышленников, обладающих продвинутыми знаниями в области клиентских технологий. Другими словами, уязвимости не станут более легкими к обнаружению, но увеличиться их опасность.

Приходилось ли вам видеть что нибудь такое, что могло бы заставить бросить сферу разработки ПО и уйти жить в бочку?

Пока не приходилось.

На какие ресурсы вы порекомендуете заглядывать, чтобы быть в курсе всех новостей из области безопасности веб-приложений?

На мой взгляд, лучшим ресурсом с подобной информацией является сайт PHP Security Consortium (http://phpsec.org/). Коллекция ссылок ресурса содержит множество линков на другие похожие сайты.

Лично я занимаюсь и другими проектами, которые могут пригодиться:

http://brainbulb.com/

http://phpsecurity.org/

http://shiflett.org/

Page 37: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Люди >> Интервью: Chris Shiflett

Вы проявляете высокую активность в PHP-сообществе сразу в нескольких направлениях. Какое из них наиболее важное для вас? Какие плоды принесло вам ваше участие?

Я думаю, что участие в конференция в качестве докладчика мне нравится более всего, так как там можно встретить много людей из сообщества «в живую». Интернет это конечно великая вещь, но он обезличивает нас при общении.

Мое участие в различных начинаниях и принесло мне то что я изучил за последние годы. PHP-сообщество – это очень отзывчивая группа людей, готовая всегда делиться информацией. Я полагаю, что в рамках сообщества мы все получаем много знаний.

Есть ли что нибудь, что вы хотели бы рассказать нашим читателям, но о чем я забыл спросить?

Сейчас ничего такого в голову не приходит.

Page 38: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Интерактивный грид своими руками

Интерактивный грид своими рукамиДмитрий Шейко

Я убежден, что пользователи избалованные GUI настольных приложений частенько находят интерфейсы веб-приложений крайне неудобными. Их, возможно, невысказанные замечания особенно уместны в эпоху AJAX. Более того, сделать веб-приложения более комфортными не так уж сложно. Я не стану в этой обзорной статье описывать все многообразие интерфейсных форм, но остановлюсь на таком незаменимом элементе как грид. Почти каждое веб-приложение нуждается в управлении списком линейных данных. Управление записями БД в PhpMyAdmin пожалуй является классическим решением в данной области. Это популярное решение, но и в нем при каждой операции требуется перегрузка страницы, возможна потеря параметров и т.д, что неудобно. Давайте подумаем, каковы требования удобного интерфейса. Пользователь должен иметь возможность сортировки списка по полям, фильтрации списка, возможность задавать диапазон выборки и постраничную навигацию. При всем при этом должна быть задействована только та часть окна, которая была подвержена изменениям.

Как вы возможно уже знаете, основа AJAX – это XMLHttpRequest. Это инструмент Java Script позволяющий выполнять запросы к удаленному серверному скрипту и получать его ответы. Таким образом, при инициации пользователем некоторого события (скажем, нажатия на пиктограмму) мы можем тот час же сообщить о его намерении серверному скрипту. Скрипт получает запрос и выясняет из переданных параметров, что ему требуется вернуть, например, отсортированный по указанному признаку список записей. Java Script получает список и добросовестно отображается его в области таблицы. Пользователь с удовольствием наблюдает, как в ответ на его действие поменялся порядок строк в таблице, однако все прочие формы рабочего окна остались неизменными.

Как это реализовать? Использование XMLHttpRequest не является сложной задачей. Впрочем, даже ее можно упростить, взяв на вооружение готовую библиотеку. Мне понравилось решение из набора YUI (http://developer.yahoo.com/yui/) именуемое Connection. С помощью незамысловатой конструкции YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); мы можем отправить POST-посылку по заданному адресу и распорядиться ответом удаленного скрипта посредством функции, назначенной в callback.

Итак, мы описываем интерфейс будущего грида в HTML. Области, зависимые от ответов серверного скрипта (список записей, индикатор числа записей списка) пропускаем, но оставляем «маячки», так что бы мы могли интерактивно управлять содержанием этих областей. Это может быть любой HTML-контейнер с заданным уникальным ID. Далее описываем функции обработки ответов сервера.

Дмитрий ШейкоВедущий веб-разработчик в Red Graphic Systems (www.redgraphic.com), автор свыше 50 технических статей. Автор проектов SAPID (http://sapid.sourceforge.net), Аспектно-Ориентированной библиотеки для PHP (победи­тель PHP Programming Innovation Award October 2005) и многих других.

Дополнительную информацию и материалы Дмитрия Шейко можно найти на его корпора­

тивном блоге http://blog.redgraphic.ru/sheiko/ и личном сайте http://www.cmsdevelopment.com/.

Адрес для связи с автором: [email protected]

Page 39: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Интерактивный грид своими руками

Например,var handleSuccess = function(o){

if(o.responseText !== undefined){document.getElementById(divName).innerHTML =

decorateList(o.responseText);}

};

var handleFailure = function(o){if(o.responseText !== undefined){

document.getElementById(divName).innerHTML = 'Server Error';}

};

var callback ={ success:handleSuccess, failure:handleFailure, argument:['foo','bar']};

Кто-нибудь наверняка сейчас задумался «Но что же мы получаем от сервера?». Мы получаем содержание консоли серверного скрипта. В самом простом случае это будет HTML обновленной таблицы. Но это подразумевает смешанные данные и их оформление. Т.е. любое изменение оформления таблицы потребует изменения серверного скрипта, что плохо скажется на «читабельности» бизнес-логики приложения. Классическое универсальное решение для передачи структур данных - XML. В этом случае мы должны будем анализировать в Java Script интерфейса переданный скриптом XML и формировать на его основе HTML или же поручить оформление XSLT. Об этом можно почитать в статье AJAX:Getting started (http://developer.mozilla.org/en/docs/AJAX:Getting_Started). Но я предлагаю использовать иной более удобный формат данных JSON (http://en.wikipedia.org/wiki/JSON). При таком подходе мы будем оперировать меньшим объемом данных, мы не будем иметь проблемы со специальными символами и нам не потребуется анализировать XML ответов серверного скрипта. JSON для Java Script – готовая к использованию структура данных.

Таким образом, нам осталось лишь определить набор параметров для различных событий и написать их обработку в серверном скрипте. Допустим при нажатии кнопки «Показать» мы передаем в серверному скрипту, взятые из полей типа INPUT TEXT номер первой записи списка (offset) и число отображаемых записей (total). Серверный скрипт подставляет эти значения в SQL запрос и оформляет запрошенный список записей в JSON. На клиентской стороне нам остается лишь «пробежаться» по массив полученных данных и оформить их в таблицу.

Как вы понимаете, нам открываются новые возможности. Мы можем заставить Java Script на клиентской стороне в случае проблемной связи с сервером автоматически повторять запросы вплоть до успешного ответа. Мы можем реализовать адекватную индикацию этого процесса «данные передаются/данные успешно переданы». Мы можем сделать фильтры более интерактивными так, чтобы при наборе каждого символа список выстраивался ревалентно уже набранной части ключа фильтрации. Впрочем, мы можем ровно столько насколько хватит нашей фантазии.

Вы можете загрузить архив со скриптами готового примера (http://www.phpclasses.org/browse/package/3481.html), описанного здесь грида.

Page 40: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Интерактивный грид своими руками

Рис. 1. Пример реализации

Рис.2. Модель

Ссылки по теме: http://en.wikipedia.org/wiki/AJAX http://en.wikipedia.org/wiki/Reverse_Ajax

http://cmsdevelopment.com/easygrid/ http://demo.sitesapiens.com/tutorials/en_records.swf

Грид – англ. Grid, решетка. Элемент управления в пользовательском интерфейсе для отображения и правки ли­нейных данных.

JSON - JavaScript Object Notation, Формат для обмена данными между приложениями.

YUI - Набор утилит и элементов управления, написанных на JavaScript для построения расширенных веб-интер­фейсов с использованием технологий DOM, DHTML и AJAX.

Толковый словарь веб-разработчика - http://phpinside.ru/phpdefs/index.php?a=index&d=1

Page 41: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Что такое XML Sapiens?

Что такое XML Sapiens?Автор: Дмитрий Шейко

1995 году компания Vignette представила на рынке первую коммерческую систему класса CMS (систем управления контентом). С тех пор число коммерческих CMS неустанно растет и ныне сам термин CMS прижился на рынке и, как правило, не требует расшифровки. За последние годы было утверждено множество отрытых стандартов, позволяющих структурировать информацию на сайтах, отделить ее от дизайна, но, по-прежнему, большинство CMS не следует им.

Так уже много лет существует стандарт XSLT, позволяющий формирование документов из разделенных источников: XML-файла со структурированным содержанием документа и XSL-шаблона с описанием того, как документ будет представлен на сайте. Причем само формирование документа, может происходить на стороне клиента. Достаточно передать браузеру XML-структуру данных, содержащую ссылку на XSL-шаблон и браузер сам «нарисует» страницу в том виде, как это предполагалось дизайнерами. Содержание каждой страницы сайта различается, однако форма подачи этого содержания, обычно, ограниченна небольшим числом шаблонов. Таким образом, XSLT позволяет нам одиножды написанный шаблон представления данных на сайте использовать многократно. Казалось бы, вот она идеальная технология для CMS. Однако повсеместное применение данной технологии сдерживает ряд факторов. Из них психологическая инерция - не главенствующий фактор. Описание функциональности сайта с помощью XSLT - весьма трудоемкая задача. Кроме того, XSL-шаблон слишком зависим от XML-документа с данными, что ограничивает гибкость решений на основе данной технологии.

Таким образом, XSLT представляет собой концептуально безупречное, но на практике трудоемкое решение. Данное обстоятельство побуждает разработчиков искать новые решения, включающие преимущества утвержденных открытых стандартов и, в то же время, относительно удобные в использовании. Одно из таких решений – декларативный язык XML Sapiens (http://www.xmlsapiens.org).

Как устроен XML SapiensТак же как и XSLT, с каждым документом сайта должен быть связан определенный шаблон. Шаблон может содержать любой код представления (например, HTML) и инструкции XML Sapiens. В шаблон могут быть, включены несколько файлов. Для этого используется инструкция sapi:include, близкая к аналогу в открытом стандарте xInclude.

<sapi:include href="адрес_файла_шаблона" parse="template" />

Прочие инструкции XML Sapiens позволяют доставить в документ содержание и функциональные блоки. Цель этого решения разделить описание структур содержания и функциональности. Это позволяет единожды создать некоторый набор каркасов структур содержания и функциональности и в дальнейшем использовать его как конструктор при построении сайта.

XML Sapiens и данныеXML Sapiens включает такое понятие как состояние интерфейса. Это позволяет определить для одной и той же страницы сайта различные наборы данных в зависимости от внешних или заданных условий. Допустим, если пользователь авторизован на сайте, страница может содержать одни поля содержания, если не авторизован другие. Состояния набора полей содержания

Page 42: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Что такое XML Sapiens?

страницы определяется в отдельном XML-документе. Для того чтобы применить набор достаточно выполнить включение набора для указанного состояния:

<sapi:include href="адрес_файла_набора_полей" parse="fieldset" state="a2" />

Набор полей содержит инструкции доставки данных. Эти инструкции связывают указанный идентификатор данных с типом поля, описанным во внешнем XML-документе.

<sapi:apply name="qc.идентификатор.value" type="тип" href="адрес_описания_типа" />

XML документ типа поля, как и в случае набора полей, может содержать описания типа для различных состояний интерфейса. Если в системе определены состояния «администрирование» и «доставка содержания», то в первом случае данные могут быть представлены в форме запроса содержания, во втором «как есть».

Page 43: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Что такое XML Sapiens?

XML Sapiens и функциональностьВ шаблоне страницы также могут содержаться инструкции запроса сценария функциональности. Алгоритм этого сценария описан в заданном XML-файле.

<sapi:apply name="ddc.menu.value" href="адрес_сценария" />

Документ описания функционального алгоритма (DDC) содержит инструкции анализа условий, аналогично XSLT. Синтаксис DDC также позволяет ссылаться на приложения CMS, которые, согласно переданным параметрам, возвращают потоки данных для дальнейшего анализа условий.

<sapi version="2.0" xmlns:sapi="http://www.xmlsapiens.org/spec/sapi.dtd">

<sapi:ddc name="sample">

<sapi:choose>

<sapi:when exp="eq(this_record_id.value,0)">

<sapi:for-each select="cms_application()" name="enum">

<sapi:params>

<sapi:param name="param1">value1</sapi:param>

<sapi:param name="param2">value2</sapi:param>

</sapi:params>

<sapi:ifempty>Records not found</sapi:ifempty>

<sapi:fallback>CMS-application error</sapi:fallback>

<sapi:choose>

<sapi:when exp="gt(this.this.переменная_из_потока_данных.value,0)">

<sapi:code>

Sample code, &this.this.переменная_из_потока_данных.value;

</sapi:code>

</sapi:when>

</sapi:choose>

</sapi:when>

</sapi:choose>

</sapi:ddc>

</sapi>

При запросе функционального сценария допускается указание параметров запроса, позволяет

Page 44: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Что такое XML Sapiens?

многократное использование функциональных сценариев.

<sapi:apply name="ddc.menu.value" href="http://site.com/ddc/menu.xml">

<sapi:param name="param1">value1</sapi:param>

<sapi:param name="param2">value2</sapi:param>

</sapi:apply>

Page 45: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Что такое XML Sapiens?

Как видите, XML Sapiens позволяет подготовить набор описаний структур данных, типов полей содержания и функциональность и в дальнейшем использовать при конструировании сайта. Возможность многократного использования этих составных элементов снижает время разработки веб-проектов, позволяет избежать системного программирования. Причем, XML Sapiens универсален. Он может применяться в CMS, написанной на любом программном языке.

Язык существует более года, а недавно была опубликована вторая версия языка. Это внушает надежду на то, что язык будет и далее развиваться и использоваться. На сегодня на базе этого языка функционируют всего несколько CMS. Однако если это число увеличится, обмен функциональными решениями между разработчиками, использующими различные CMS может стать обычным делом.

Ссылки по темеРусскоязычный вариант спецификации XML Sapiens 2.0: http://xmlsapiens.org/spec/ru_sapi20.pdf

Пресс-релиз о новый версии языка: http://sitesapiens.ru/news/4256/

Page 46: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

Шифрование в PHP для обычных людейАвтор: Thomas Myer, Перевод: Андрей Олищук

В этом все более виртуализирующемся онлайн-мире вам необходимо быть настороже, чтобы защитить свои данные. В этом руководстве мы предлагаем немного полезной информации о том, как можно зашифровать важную информацию – пароли, номера кредитных карт и даже целые текстовые сообщения. Здесь мы поговорим о том, что означают понятия «зашифровать» и «дешифровать», а так же рассмотрим примеры с использованием стандартного функционала PHP.

Подумайте, как отличается сегодняшний день от того, что было 20 лет назад. В те давние восьмидесятые годы шифрование было «шпионской штучкой», чем-то таким, о чем можно было прочитать в технических триллерах Тома Кленси. Если кто либо хотел сохранить информацию в секрете, он закрывал ее паролем, ключевой фразой или другим простейшим способом.

Сегодня же, шифрование повсюду окружает нас. Пароли хранятся зашифрованными в базах данных, шифрованные туннели через киберпространство доступны через SSL и SSH и мы не говорим уже о виртуальных частных сетях (VPN). Каждый день люди используют PGP для защиты своих файлов и электронных почтовых сообщений.

Как PHP-разработчик, вы должны знать, что основы безопасности предназначены не только для каких-то экзотических приложений – они нужны и тому проекту, над которым вы сейчас работаете. Эти основы начинаются с «детского сада» (вроде сокрытия текста пароля при вводе в форме) и доходят до таких «умных» терминов криптографии как DES, MD5, SHA1 и Blowfish.

Здесь нам не хватит времени и места, чтобы обсудить все аспекты шифрования, но мы сможем преподать основы, закрывающие большинство ваших повседневных ситуаций. Начнем руководство с разъяснения – что означает зашифровать и дешифровать информацию, затем последуют несколько практических примеров с использованием стандартной функциональности PHP. На протяжении всего руководства, шифрование будет рассматриваться шире, чем в контексте безопасности. И, наконец, мы рассмотрим плагины и расширения PHP, относящиеся к нашей теме.

Криптографический примерКриптография, это искусство «секретного письма», о чем нам говорит перевод термина с греческого. Одним из первых и простейших шифров является «тайнопись цезаря», в которой каждая буква исходного текста смещается на n позиций алфавита, а результат и является зашифрованным. К примеру:

Открытый текст: Veni Vidi ViciЗашифрованный: Xgpk Xkfk Xkek

Изучая зашифрованный текст, вы можете прийти к эвристическому заключению, что буквы смещены на две позиции вправо. Такой шифр очень легко взломать. К примеру: изучите зашифрованное сообщение и обратите внимание, что буква «X» повторяется очень часто, как и буква «к». Можно предположить, что исходные буквы представляют собой гласные звуки (в латинском алфавите V может быть гласной – прим. редактора) так как часто встречаются на

2

Page 47: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

соответствующих местах в четырехбуквенных словах. Как только вы определите гласные, то найдете ключ к разгадке и остальных букв. Конечно, нелишним будет знание, что зашифрованный текст написан на латыни, но здесь мы привели пример для общего понимания сути.

Современные технологии шифрования гораздо мощнее. Они используют алгоритмы, идущие дальше чем простая перестановка букв и символов. Здесь мы не будем детально рассматривать эти алгоритмы, но упомянем, что практически любая инсталляция PHP содержит в себе все, что понадобится для сохранения данных на приемлемом (и даже на очень хорошем) уровне безопасности.

В PHP, конечно, нет стопроцентных не взламываемых методов, обеспечивающих высокопрофессиональный уровень современной криптографии. В наше время не бывает месяца, когда какой-нибудь хакер вместе со своими друзьями не объединили бы тысячу машин и не взломали очередной новейший алгоритм, в том числе методом обычного перебора вариантов. Но в любом случае, ваши системы будут под вполне надежной защитой, достаточной для того, чтобы хакеры не брались за ее взлом – у них есть огромное количество менее защищенных потенциальных жертв.

Держа сказанное выше в уме, перейдем к простейшему PHP-приложению, защищенному обычной формой логина.

Обработка форм в PHP без обеспечения безопасности шифрованияДавайте предположим, что вы начинающий веб-разработчик и вам не приходилось особенно играться с функционалом по безопасности. Вы создали свое первое приложение, которое сохраняет имена пользователей и пароли в предназначенной для этого таблице, но не стали шифровать пароли. Соответственно, они находятся в базе в чистом виде и открыты для всех, кто имеет доступ к базе данных. Для работы с этими данными вы можете создать страницу наподобие этой:

<form action="verify.php" method="post"><p><label for='username'>Username</label><input type='text' name='username' id='username'/></p><p><label for='password'>Password</label><input type='text' name='password' id='password'/></p><p><input type="submit" name="submit" value="log in"/></p></form>

Что не так с HTML-разметкой? Тип ввода, выбранный для пароля является открытым текстом и при вводе пароль будет виден на экране.

Можно легко изменить тип ввода на «password» и тогда все что пользователь введет в поле будет представлено в виде звездочек. Детский сад? Абсолютно! Но этот момент обязательно необходимо учитывать, так как он способен доставить много неприятностей связанных с безопасностью. Будете ли вкладывать деньги в банк, в офисе которого разбиты окна? Возможно. Но скорее всего вы будете ожидать от банка защиты ваших средств. То же самое относится к веб-приложению.

3

Page 48: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

Давайте взглянем на verify.php, который принимает и обрабатывает данные.

<?php$user = $_POST['user'];$pw = $_POST['password'];$sql = "select user,password from users where user='$user' and password='$pw' limit 1';$result = mysql_query($sql);

if (mysql_num_rows($result)){//we have a match!}else{//no match}

?>

Подождите прежде чем начать ухмыляться читая это. Тех из вас, кто ждет части статьи о шифровании я попрошу быть терпимее, так как шифрование это лишь часть паззла безопасности. Ведь неважно, сколько раз вы будете шифровать пароли, но если оставить уязвимость при вводе данных, то все шифрование пойдет прахом. Вы должны следовать проверенным принципам безопасности: «никогда не доверяйте внешним данным» и «обеспечьте всестороннюю защиту». Скрипт с проверкой поступающих данных:

<?php$user = strip_tags(substr($_POST['user'],0,32));$pw = strip_tags(substr($_POST['password'],0,32));

$sql = "select user,password from users where user='". mysql_real_escape_string($user)."' and password='". mysql_real_escape_string($pw)."' limit 1';$result = mysql_query($sql);

if (mysql_num_rows($result)){//we have a match!}else{//no match}?>

Благоразумно используя strip_tags(), substr() и mysql_real_escape_string(), вы вырезаете потенциально опасных команд, урезаете строки до 32 символов и экранируете подозрительные символы, которые могут быть распознаны базой данных как специальные инструкции.

В итоге этого процесса вы все равно имеет пароль в чистом виде внутри базы. Это нельзя оставить просто так. Простейший способ поправить дело - использовать встроенную функцию crypt().

Использование crypt()Функция PHP crypt() реализовывает односторонне шифрование или одностороннее хеширование. Односторонним оно называется потому как однажды зашифрованный текст не может быть восстановлен в исходном виде. Для новичка такое кодирование может показаться бесполезным и нелепым. Смысл в том, чтобы защитить данные, а уже потом использовать их.

4

Page 49: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

Не отчаивайтесь. Схемы одностороннего шифрования и crypt() в частности, являются очень популярными способами защиты информации. Если вы потеряете список пользовательских паролей, то практически исключена ситуация их использования злоумышленниками.

Давайте вернемся к примеру с паролями. Зачастую, в РНР-приложениях существуют модули, которые позволяют системным администраторам создавать, редактировать и удалять пользователей. Перед тем как сохранить данные пользователя в таблицу базы, пароль желательно зашифровать, к примеру, функцией crypt().

<?php$user = strip_tags(substr($_POST['user'],0,32));$pw = strip_tags(substr($_POST['password'],0,32));

$cleanpw = crypt($pw);

$sql = "insert into users (username,password) values('".mysql_real_escape_string($user)."','".mysql_real_escape_string($cleanpw)."')";//.....etc....?>

Crypt() получает в качестве первого аргумента строку «плоского» текста а также «соль», значение влияющее на механизм случайных чисел в алгоритме шифрования и генерирует односторонний шифрованный текст (хеш). Если вы не передадите второй аргумент, то PHP возьмет за основу значение по умолчанию, которое может быть одним из следующих:

• CRYPT_STD_DES – Стандартное DES-шифрование с двузначной «солью».

• CRYPT_EXT_DES – Расширенное DES-шифрование с девятизначной «солью».

• CRYPT_MD5 - MD5 шифрование с двенадцатизначной «солью», начинающейся с $1$

• CRYPT_BLOWFISH - Blowfish шифрование с шестнадцатизначной «солью», начинающейся с $2$ или $2a$.

Многие современные инсталляции PHP используют соль с MD5 и выше, состоящую из 12 символов, но это не всегда так. Вы можете проверить настройки своего сервера небольшой строчкой кода:

<?php echo "System salt size: ". CRYPT_SALT_LENGTH; ?>

В ответ можно получить значения 2, 9, 12 и 16 по которым и следует определять используемый по умолчанию алгоритм. Одновременно с crypt() иногда стоит применять и функцию md5() для зашифровки плоского текста и передачи его в crypt() в качестве «случайной» соли (см. листинг ниже). Функция md5() преобразует передаваемую ей строку в хэш длинной 32 символа. Впрочем, вы можете применять и любой другой метод по вашему вкусу и в соответствие с установленной политикой безопасности.

<?php$user = strip_tags(substr($_POST['user'],0,32));$pw = strip_tags(substr($_POST['password'],0,32));

$cleanpw = crypt(md5($pw),md5($user));

$sql = "insert into users (username,password)

5

Page 50: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

values('".mysql_real_escape_string($user)."','".mysql_real_escape_string($cleanpw)."')";//.....etc....?>

Теперь в базе данных хранится зашифрованный пароль, восстановить который не представляется возможным. Зачем он тогда нужен? Все просто: по аналогичной схеме шифруйте полученные от пользователя данные и сравнивайте результат с вашим образцом.

<?php$user = strip_tags(substr($_POST['user'],0,32));$pw = strip_tags(substr($_POST['password'],0,32));$cleanpw = crypt(md5($pw),md5($user));

$sql = "select user,password from users where user='". mysql_real_escape_string($user)."' and password='". mysql_real_escape_string($cleanpw)."' limit 1';$result = mysql_query($sql);

if (mysql_num_rows($result)){//we have a match!}else{//no match}?>

К примеру, если записанный в базе зашифрованный пароль выглядит как i83Uw28jKzBrZF, зашифруйте поступивший от пользователя (к примеру из формы логина) пароль, зашифруйте его и сравните. Единственный способ взломать зашифрованный пароль – подобрать его методом перебора из большого списка строк, зашифрованных по вашему методу. Это довольно распространенный метод взлома, поэтому не рекомендуется для паролей использовать имена главных героев Стар Трэка или кличку любимой собаки.

Если вы зашифруете слово Fido и на выходе получите тарабарщину, то это не будет значить, что пароль довольно безопасен. Убедитесь, что пароль состоит из большого количества символов (не менее восьми) и содержит символы в верхнем и нижнем регистрах, а также одновременно состоит из букв, цифр и спецсимволов, вроде знака доллара $ или восклицательного знака. Угадать такой пароль практически невозможно. Даже строка «f1D0!» Будет лучшим вариантом, чем, скажем «ГендальфСерый». Хотя последний пароль длиннее, содержит символы в обоих регистрах – он подбираем, так как представляет собой имя одного из героев «Властелина колец».

Как не следует использовать Crypt()Есть еще один метод использования crypt(), но он являет собой скорее плохой пример. В качестве соли берется n количество символов от изначальной строки плоского текста.

<?php$user = strip_tags(substr($_POST['user'],0,32));$pw = strip_tags(substr($_POST['password'],0,32));$cleanpw =crypt($pw, substr($user,0,2));

$sql = "select user,password from users where user='". mysql_real_escape_string($user)."' and password='". mysql_real_escape_string($cleanpw)."'

6

Page 51: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

limit 1';$result = mysql_query($sql);

if (mysql_num_rows($result)){//we have a match!}else{//no match}?>

Если ваш логин «tmyer», то соль будет содержать в себе префикс «tm» и злоумышленнику будет легче догадаться, что вы использовали в качестве соли и, соответственно, подобрать весь пароль. Не очень хорошая идея.

Шифрование и дешифрование с PHPБольшая часть данной статьи была посвящена одностороннему шифрованию с помощью crypt(). Но что если перед вами стоит задача отправки зашифрованных сообщений с возможностью их дальнейшей расшифровки легальным получателем? Используйте шифрование с публичным (открытым) ключом, которое тоже поддерживается в PHP.

Пользователи шифрования с открытым ключом получают в свое распоряжение открытый публичный ключ и секретный закрытый ключ. Публичными ключами пользователи обмениваются между собой. Если вы хотите послать тайное сообщение своему другу Джону, вы шифруете свое сообщение его публичным ключом. Как только Джон получит зашифрованное сообщение, он расшифрует его с помощью своего закрытого ключа. Публичный и закрытый ключи между собой никак не связаны математически, поэтому по открытому ключу никак нельзя сгенерировать закрытый ключ.

В методике шифрования PGP к примеру, в качестве закрытого ключа используется даже не секретное слово, а целая фраза, которая может содержать любые символы, включая пробелы.

Одним из способов применения публичных ключей основанных на PGP является использование GNU Privacy Guard (GPG). Любое сообщение, зашифрованное и помощью GPG может быть расшифровано с GPG, PGP или при помощи различных плагинов к почтовым клиентам. В следующем примере, онлайновая форма принимает пользовательский ввод, шифрует сообщение для конкретного получателя по схеме GPG и отправляет его.<?php//set up users$from = "[email protected]";$to = "[email protected]";

//cut the message down to size, remove HTML tags$messagebody = strip_tags(substr($_POST['msg'],0,5000));$message_body = escapeshellarg($messagebody);

$gpg_path = '/usr/local/bin/gpg';$home_dir = '/htdocs/www';$user_env = 'web';

$cmd = "echo $message_body | HOME=$home_dir USER=$user_env $gpg_path" ."--quiet --no-secmem-warning --encrypt --sign --armor " ."--recipient $to --local-user $from";

7

Page 52: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

$message_body = `$cmd`;

mail($to,'Message from Web Form', $message_body,"From:$from\r\n");

?>

В этом примере, PHP обращается к /usr/local/bin/gpg (этот путь может меняться в зависимости от вашего Linux-сервера) с «просьбой» зашифровать сообщение с использованием закрытого ключа отправителя и открытого ключа получателя. В итоге, только указанный получатель сможет прочесть сообщение и будет точно знать откуда пришло письмо. Установки переменных окружения HOME и USER указывают GPG где искать хранилище ключей. Остальные флаги означают:

• quiet и --no-secmem-warning подавляют уведомления от GPG.

• encrypt осуществляет шифрование.

• sign добавляет подпись для верификации отправителя.

• armor производит ASCII-вывод вместо бинарного файла, поэтому данные легко передаются по электронной почте.

Обычно подразумевается, что закрытые ключи защищены секретной фразой. Приведенный выше пример не использует фразы, так как ее потребовалось бы вводить вручную при каждой отправке из формы. Здесь можно использовать другие возможности, к примеру передачу секретной фразы системе с помощью хранящегося на сервере отдельного файла или закрытия формы от незащищенного публичного доступа (чтобы исключить перехват фразы при вводе).

В любом случае учтите, что не смотря на использование SSL, текст сообщения все равно передается в плоском виде, а значит виден при передаче между машиной клиента и сервером. О это уже другая тема.

ЗаключениеЯ рассказал вполне достаточно об основах безопасности, технике шифрования и даже о закрытии информации с помощью публичных ключей чтобы вы смогли использовать полученные знания в своих РНР-проектах. Всегда нужно помнить, что любое шифрование никогда не гарантирует 100% безопасности от взлома. Единственный способ обезопасить информацию от хакеров на своем компьютере – это выключить систему из розетки. И то, остается вероятность что кто-то физически появится в серверной комнате, включит машину и украдет данные. Главная задача шифрования – отбить охоту у хакеров даже к попыткам взлома.

Основная проблема защиты данных – баланс между удобностью использования и уровнем защиты. Одностороннее шифрование надежно закрывает информацию, но делает ее неудобной для чтения, но с другой стороны обычный текст будет удобен и понятен, но в незашифрованном виде он будет понятен и злоумышленнику. Соблюдать равновесие можно используя серьезные методы для шифровки важных данных (номера кредитных карт, паролей доступа) и более-менее приемлемых способов защиты остальной информации.

8

Page 53: #19, 2007 :: Путь к оптимизации MySQL

PHP Inside'19 >> Идеи >> Шифрование в PHP для обычных людей

Полезные ссылки по теме:• Для начала прочтите информацию о принципах криптографии (требует регистрации):

https://www6.software.ibm.com/developerworks/education/s-crypto/

• Проверка PHP-приложений на безопасность: http://www-128.ibm.com/developerworks/edu/os-dw-os-php-lockdown.html

• Шифрование с открытым ключом в Wikipedia: http://en.wikipedia.org/wiki/Public-key_cryptography

• Руководство по шифрованию в РНР: http://www.webmonkey.com/programming/php/tutorials/tutorial1.html

• Хеширование паролей: http://phpsec.org/articles/2005/password-hashing.html

Оригинал статьи: http://www-128.ibm.com/developerworks/opensource/library/os-php-encrypt/?ca=dgr-btw04PHP-encrypt


Recommended