По ту сторону Веб-страницы

Филиппика против баз данных

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

«В настоящий момент база данных недоступна» или «Не удается подключиться к базе данных»?

Рассмотрим проблему под разными углами.

Базы данных являются замечательным средством хранения дан­ных. Современные электронные базы данных, кроме того, предостав­ляют мощный и удобный инструментарий для работы с этими данны­ми, а именно — язык запросов SQL. Благодаря этому языку возможно не только добавлять, удалять, просматривать и редактировать данные, но и представлять их в разной форме. Чего стоят только возможности сортировки, ассоциации разных таблиц базы друг с другом и — одно из самых замечательных свойств — возможность обращения только к части данных. С текстовыми файлами так работать нельзя: можно только прочитать весь файл, и на основе его делать выборку значений, либо читать файл до первого (второго, третьего) вхождения — здесь нет стандартизированного средства запросов к фрагментам файлов.

Представим ситуацию. Нам необходимо размещать на сайте ин­формацию о трех тысячах книг в магазине букинистической литерату­ры. Для выполнения этой задачи есть два пути: записывать данные в БД или в файлы.

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

Alter table [имя таблицы]

Add [имя нового поля] char(50);

Сценарий второй. Разработчик понимает, что информацию о 3000 книг в одном текстовом файле держать неудобно, потому что для поис­ка сведений о нужных книгах каждый раз сценарий будет его открывать, записывать в строку или, того хуже, в массив (массивы потребляют мно­го ресурсов интерпретаторов языка), а только потом обрабатывать и из­влекать данные. Страшно подумать, как это будет медленно работать и из-за скольких нелепых случайностей текстовая БД будет стираться напрочь. Возникает резонный вопрос: по какому принципу разделять информацию на 20 файлов, чтобы при этом скрипт-анализатор сразу обращался к нужному файлу? По фамилии автора? А если у него не было фамилии? (В самом деле, какие фамилии были у Платона и Гомера?) Тог­да по первой букве названия книги? Но тогда при поиске сценарий все равно будет считывать все файлы, чтобы найти нужный кусочек текста. А если пойти на крайнюю меру и каждую книгу записывать в отдельный файл? Нет, это уже слишком. Останавливаемся на варианте «30 файлов для начала, в каждом не более 100 записей, при создании новых записей создается новый файл еще на сто записей». Файлы — формата XML или простые текстовые с разделителями для имитации полей БД. От считы­вания файлов в строки, разделения их на фрагменты по разделителям и занесения фрагментов в массив никуда не деться. Для сортировки пи­шется длинный и нудный сценарий; подходящего готового в интернете не нашлось, потому что все предпочитают работать с базами данных.

Но вот все готово. Приходит руководство, одобрительно изучает сайт и говорит:

— Да, вот еще что я забыл. У каждой книги должно быть еще ука­зано, когда она поступила в магазин.

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

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

Филиппика против баз данных

4.8

Из тридцати файлов в конце каждой строки еще по одному разделите­лю, а после него теоретические новые данные. Увлекательную работу по ручному набору дат он оставляет на закуску. Затем — еще кусок сце­нария для пользователей, чтобы они могли сортировать данные по дате поступления в магазин (именно так наверху рейтинга появляется ин­формация о новых поступлениях). После этого ему приходит в голову, что директор придумает еще одно поле, и тогда придется делать еще одно дополнение. Он скрипит зубами, переписывает фрагмент «админ­ки», чтобы можно было добавлять новые разделители и новые данные через веб-интерфейс. Все готово. Остались даты. Но за окном уже ночь, одна знакомая девушка уже спит, а вторая ужинает в кафе за одним сто­ликом с любителем баз данных... Все следующие сайты разработчик уже строит с помощью БД.

Вывод один: базы данных незаменимы для больших объемов од­нотипных данных. Или небольших объемов, которые со временем гро­зятся вырасти в большие. Объемов, которые можно структурировать, делать из них выборки, сортировать в разной последовательности.

Но в некоторых случаях работа с файлами оказывается удобнее.

Чаще всего с файлами работать логичнее, когда структура различ­ных страниц отличается друг от друга. Например, одна страница явля­ется сценарием и «обслуживает» порядка двухсот страниц, видимых по­сетителю (то есть это посетитель думает, что страниц двести, а на самом деле страница одна, только с разным содержимым). Еще тридцать стра­ниц являются текстовыми файлами, содержащими авторские произве­дения, без какой бы то ни было разметки (просто первая строка у них отвечает за заголовок, остальные разбиваются на абзацы скриптом), которые приводятся в нужный вид общим для них сценарием и добав­ляют сведения об авторстве. Наконец, один файл представляет собой текстовую базу данных: ради двадцати или тридцати строк полновесную БД заводить неудобно, а текстовый файл такого объема анализируется мгновенно.

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

Во-первых, это простые списки данных, каждый фрагмент на но­вой строке (файл login. txt):

Anna

Vladimir

*Toxa*

Solnce

Debil

Cool Girl =Beast=

Serge

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

<?

$logins = File("login. txt"); // Создаем массив echo "Все зарегистрировавшиеся: ";

Foreach($logins as $value) і

Echo $value."<br />"; // Вывод всего списка і

?>

Чуть сложнее работать со вторым типом текстовых БД, услов­но — «текстовые БД с разделителями». Мы захотели сделать в чате пол участника, женский (f), мужской (m) или без указания пола (n) — файл gender. txt

Anna = f Vladimir = m *Toxa* = m Solnce = n Debil = n Cool Girl = f -=Beast=- = m Serge = m

Сценарий не просто заносит в массив каждую строку, но и разби­вает ее на имя пользователя и пометку о поле:

<?

$logins = File("login. txt");

// Создаем массив

$gender transform = array("f" => "девушка",'^" => "парень","п" => "существо неясного пола"); echo "Все зарегистрировавшиеся: ";

Foreach($logins as $value) і

List($name,$gender) = explode(" = ",$value);

// Разбивка на имя и пол

Echo $name.", ".$gender transform[$gender]."<br />";

// Вывод всего списка с указанием пола уже по-русски

}

?>

Тут же вскрывается слабое место подобных текстовых БД. Ведь кому-то из пользователей придет в голову использовать в имени знак равенства с пробелами по бокам, который является разделителем. Зна­чит, о такой ситуации нужно позаботиться заранее и при регистрации запретить использование данной последовательности символов.

Наконец, третий тип основан на XML.

По сравнению с текстовыми БД с разделителями этот тип более стабилен с точки зрения возможности запросов информации, его струк­тура более наглядна, и значит, с ней проще работать. Минус же состо­ит в том, что объем этих файлов больше. Для наглядности рассмотрим один пример. Допустим, в 2007 году сделано 2 сайта, а в 2006 — только один. Данные нужно представить примерно в таком виде:

Работы за 2007 год (2 шт.)

Меловой период Www. cretaceous. ru

Геологический сайт

Сервер задач backstage. erlang. com. ru

Секретный сайт

Работы за 2006 год (1 шт.)

Консалтинг+ Www. konsplus. com

Юридические услуги

Такую верстку несложно сделать вручную, поскольку работы всего три. Но если количество работ увеличивается как минимум каждые две недели и не ограничивается двумя годами, «ручная работа» перестает оправдывать себя. При изменении данных в одном фрагменте портфо­лио нужно вручную менять данные во всех остальных фрагментах тако­го же типа. Если определенный класс работ нужно на время скрыть, то приходится делать копию файла с полным списком, а урезанный файл загружать на сервер. Если потребуется использовать фрагмент данных (последняя работа; самая первая работа; данные за определенный год), то эти данные придется переписывать вручную.

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

Один из вариантов XML-ориентированной текстовой базы дан­ных, где представлена уже упоминавшаяся информация, может выгля­деть так:

<2007>

<item>

<addr>www. cretaceous. ru</addr>

<name>Мeловой пepиод</name>

<descг>Гeологичeский сайт</descг>

</item>

<item>

<addг>backstage. eгlang. com. гu</addг>

<name>Сepвep задач</name>

<descr>CeKpeTHbrn сайт</descr>

</item>

</2007>

<2006>

<item>

<addг>www. konsplus. com</addг>

<name>Консалтинг+</name>

<descг>Юpидичeскиe услуги</descr>

</item>

</2006>

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

Нетрудно понять, что условно созданные «тэги» обозначают (сло­во «тэги» в кавычках, потому что такие тэги предусмотрены не строгой спецификацией, а скорее фантазией разработчика). Общего тэга нет: он избыточен. Наиболее крупное деление информации — по годам, и имена «верхних» тэгов представляют собой числа. Каждый элемент (<item>) портфолио включает в себя название сайта, его адрес и крат­кую аннотацию. Естественно, такое скупое портфолио вряд ли уместно на профессиональном сайте; сейчас мы разбираем только пример.

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

<?

// Считываeм файл в CTpoKy

$str1 = file get contents("file. php");

Филиппика против баз данных

4.8

// Циклом проходим по годам for($j=date("Y"); $j>=2006; $j--)

{

// Каждый год теперь — отдельная строка:

$god = XMLer($str1,$j);

// Вычисляем количество работ в году (функция substr count()):

Echo '^2>Работы за '.$j.' год ('.substr count($god,"<item>").' шт.)</h2>';

// C помощью своей функции CyXMLer() считываем // содержимое каждого элемента <item>

// и преобразовываем в нужный вид с помощью // косвенного вызова функции portfolio() CyXMLer($god,"item","portfolio");

}

?>

Эта функция помещается в том месте страницы, где происходит вывод данных в браузер. Естественно, до этого нам надо написать фун­кцию CyXMLer(): она циклически (с помощью функции XMLer() — ее тоже надо описать) извлекает данные из заданных во втором параметре тэгов (задан тэг <item>) в указанной строке (строка передается пере­менной $god, а до этого определяется как строка — работы за отде­льный год).

Вот эти две функции:

<?

// Системные функции

Function XMLer($string name,$tag name) // Простое извлечение из тэгов {

$tag name = explode("/",$tag name); foreach($tag name as $tag name)

{ _ _

$tag name = strtolower($tag name);

If(strpos($string name,$tag name)===false)

{

$tag name = strtoupper($tag name);

}

$tagnu = strlen($tag name)+2;

$begi = strpos($string name,"<".$tag name.">")+$tagnu;

$string name = substr($string name,$begi);

$fini = strpos($string name,"</".$tag name.">"); $fini = trim(substr($string name,0,$fini));

}

Return $fini;

}

Function CyXMLer($string,$tag,$func) //

Циклический перебор {

$item grance = "0";

$tag1_= "</".$tag.">"; while(strpos($string,$tag1))

{

$func($string);

$item grance = strpos($string,$tag1) + strlen($tag1);

$string = substr($string,$item grance);

}

}

// Системные функции закончились?>

Рассмотрим вкратце, как это работает. Функция XMLer() полу­чает в качестве входных параметров имя строки и имя тэга (угловыми скобками она оформляет имя тэга сама). На тот случай, если тэги переда­ются то в верхнем регистре, то в нижнем, производятся служебные пре­образования. Так, если функции передается некая строка (текст) и имя тэга «ТЭГ», то она извлечет из текста «Как ныне сбирается <ТЭГ>вещий Олег</ТЭГ> отмстить <ТЭГ>неразумным</ТЭГ> хазарам» слова «ве­щий Олег», поскольку встретит это сочетание, обрамленное указанным тэгом, и на этом успокоится. Слово «неразумным» останется за преде­лами ее видимости.

Но если необходимо учесть все вхождения с этими тэгами (а это актуально для нас, поскольку фрагменты <item>...</item> за год могут встретиться несколько раз), подключается функция CyXMLer(), кото­рой передаются не только имена строки и тэга, но и имя функции (без скобок), которая совершит с извлеченными из тэгов данными нужные операции (выстроит в ряд, оформит иным способом, добавит в массив, уничтожит и т. п. — это зависит от потребностей разработчика). Функция ищет тэг от начала файла, когда находит, передвигает начальную грани­цу поиска за заключающий тэг и ищет после этой границы, передвигая ее, пока не достигнет конца файла. Теперь мы можем быть уверены, что ни одно вхождение не пропущено. Наконец, функция CyXMLer(), на­ходя нужный фрагмент и извлекая его из тэга, вызывает функцию пре­

Образования, произвольно названную разработчиком (сейчас она у нас названа «portfolio() »). Для полноты картины приведем и ее:

<?

// Функции преобразования function portfolio($string)

{

Echo "nn";

Echo '<p><a href="http://'. XMler($string,"addr").'" target="_blank">'. XMler($string,"name").'</a> &nbsp; <span style="color:#CCCCCC">'.XMler($string,"addr").'</ span><br />';

Echo XMler($string,"descr").'</p>'; echo "nn";

}

// Функции преобразования закончились ?>

Здесь комментарии почти излишни, но кое-что требует поясне­ния. Функция принимает в качестве входного параметра строку, но не ту, которую принимала CyXMLer(), а уже ту, которую ей последняя переда­ет. Поскольку во время циклической обработкой функцией CyXMLer () строки функция portfolio() вызывается несколько раз, но каждый раз обрабатывает разные фрагменты этой строки. Такие функции пре­образования пишутся под конкретные текстовые базы данных. Общее в них может быть одно: с помощью функции XMLer () они извлекают содержимое разных вложенных тэгов и приводят полученные фрагмен­ты информации в нужный вид. Данную функцию можно усовершенство­вать: проверять, содержит ли строка в тэге <addr> название протокола (http: //), и если содержит, удалять, поскольку название протокола уже подставляется функцией. Переводы строк (символы n) нужны только для того, чтобы код получался красивее, а не сливался в один абзац.

Функции преобразования должны предшествовать системным функциям.

Чтобы показать реальную картину, можно представить себе, как будет выглядеть шаблон одного элемента для реального портфолио. Следует учесть, что некоторые тэги в пределах одного элемента спис­ка могут повторяться: дело в том, что в описании сайта может быть не­сколько скриншотов, а в процессе могут участвовать несколько дизай­неров. Разберитесь в значениях тэгов сами:

<2007>

<item>

<view>

<addr></addr>

<пате></пате>

<favicon></favicon>

<descr></descr>

<Бсгееп>

<ітаде></ітаде>

<addr></addr>

<subscr></subscr>

</зсгееп>

<Бсгееп>

<ітаде></ітаде>

<addг></addг>

<subscг></subscг>

</Бсгееп>

</view>

<stuff>

<diгectoг></diгectoг>

<designeг></designeг>

<designer></designer>

<ргодгаттег></ргодгаттег>

<codeг></codeг>

<flasheг></flasheг>

</stuff>

^ресіа1>

<info></info>

<thanx></thanx>

</special>

<item>

</2007>

При работе как с текстовыми, так и с настоящими базами дан­ных есть свои преимущества и недостатки. Например, полноценные базы данных не очень удобно использовать, если данных мало (неко­торые хостеры взимают за использование БД отдельную плату); БД труднее, чем файлы, переносить с сервера на сервер; базы данных чаще отказывают, если велика нагрузка на сервер (при этом текстовые фай­лы продолжают доставляться в браузер). Но для больших объемов од­нотипных данных текстовые файлы непригодны. Специализированных функций для обращения к части файлов и сортировки данных внутри файлов (если это не массивы) нет. Если отсутствие файла проверяется простой функцией, а его содержимое бывает недоступным, только если файла нет на самом деле, то БД иногда бывают недоступны по другим причинам, и программисту приходится на каждый фрагмент в месте потенциального отказа писать тексты, которые будут видимы посети-

Польза настроечных файлов

4.9

Телю в случае ошибки. Грамотные сообщения об ошибках написать це­лая проблема, судя по конкретным сайтам. Кто-то пишет «Troubles with database» или «Can’t connect to MySQL Server» (почему по-английски — неясно), кто-то — «База данных недоступна, повторите попытку позже» (пользователь не обязан знать, в чем на сайте хранят информацию, ему важнее знать, когда он ее получит), а кто-то — «Сервис временно недо­ступен. Мы знаем. Повторите попытку позднее» (никаких извинений, только высокомерное «Мы знаем»). В первую очередь нужно обеспе­чить отказоустойчивость системы, а сообщения об ошибках сделать бо­лее полезными («Информация станет доступной через 17 минут», «Если вы видите это сообщение, на сайте возникли проблемы. Будьте добры, напишите об этом разработчику: адрес» и т. п.).

P. S. Филиппики не получилось. Опять получился призыв снача­ла работать головой, а потом руками.

4.9. Польза настроечных файлов

В разделении данных на фрагменты есть несомненная польза.

К примеру, вы делаете сайт для заказчика, и на главной страни­це указан адрес его электронной почты. Возникает закономерная мысль: а если заказчик поменяет свой электронный адрес, значит ли это, что старый адрес будет висеть на странице до страшного суда? Обратится ли заказчик к разработчику снова или постарается отредактировать файл сам? И случайно сотрет там кавычку...

Простейший выход — записать адрес электронной почты в отде­льном файле, а на администраторской странице сделать возможность редактировать этот адрес. В «админке» появляется раздел «Настройки сайта», в котором, помимо каких-то мелочей, владелец может поменять и адрес своего сайта.

Но на достигнутом остановиться сложно. Есть и другие вещи, ко­торые можно настраивать:

— количество новостей (или записей блога), которое будет выво­диться на главной странице;

— количество символов, максимально допустимое в новости (или записи в блоге) на главной странице, после которого запись об­режется, а на месте скрытого текста появится ссылка на полный текст новости («Полный текст», «Читать целиком» или просто стрелка вправо — &rarr;);

— количество результатов на поисковой странице;

— отображение или скрытие тех или иных страниц на сайте, в том числе отображение или скрытие соответствующих пунктов меню;

— показывать ли адрес электронной почты или ссылку на страницу, с которой можно отправить письмо, не загружая почтовую про­грамму;

— выбор кодировки для страниц и другие параметры, зависящие от тематики конкретного сайта.

Настроечный файл можно записывать на сервер в любом удобном формате, главное — чтобы из него было удобно автоматически считы­вать информацию. Например, вид может быть XML-ориентированным:

<mail>

<address>12 3@domain. ru</address>

<show>1</show>

</mail>

<news>

<quantity>15</quantity>

<length>4 0 0</length>

</news>

<search>

<quantity>10<quantity>

</search>

Если использовать сценарий, предложенный при описании PHP, то вызов настроек будет происходить примерно так:

$addr = XMLer("prefs. txt","mail/address");

Можно сделать настройки экономнее, чтобы чтение этого файла происходило быстрее:

Mail: 123@domain. com mail-show: 1

News-q: 15 news-l: 400 search: 10

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

$addr = prefs["mail"];

Сценарии, для которых настраиваются параметры, немного мо­дифицируются. Перед выполнением сценарий проверяет значение па-

Польза настроечных файлов

4.9

Раметра, и в зависимости от этого выполняется в разных вариантах либо вообще не выполняется.

Вообще фрагментарность хранения информации заложена в при­нципы построения веб-страниц изначально: отдельно можно хранить HTML-файлы, изображения, ролики, аудиофайлы, стилевые файлы и сценарии. А при использовании файлов сценариев страницы вообще можно составлять на лету из десятков файлов. Именно этот принцип и можно использовать при работе с настройками.

Приложения

По ту сторону Веб-страницы

Словарь

Ботки. Обычно расширения состоят из трех букв (exe, gif, php, mov, bmp, eps, swf, asp, m3u, avi, rtf, txt, zip, cpp), но встречаются также двухбуквенные (js, ai) и четырехбуквенные (html, …

Справочник для внутреннего использования

Навигация есть признание того, что твоя страница далека от иде­ала. Ибо если бы она была близка к нему, зачем бы потребовалось покидать ее? А если ее не требуется покидать, зачем …

Алфавит от Google

Есть такая тестирующаяся поисковая подсистема от Google (Http://Www.Google.Com/Webhp?Complete=1&Hl=En), в которой по введенным первым буквам предлагаются наиболее часто за­прашиваемые слова. Я собрал все первые (наиболее рейтинговые) слова на каждую букву русского …

Как с нами связаться:

Украина:
г.Александрия
тел./факс +38 05235  77193 Бухгалтерия

+38 050 457 13 30 — Рашид - продажи новинок
e-mail: msd@msd.com.ua
Схема проезда к производственному офису:
Схема проезда к МСД

Партнеры МСД

Контакты для заказов оборудования:

Внимание! На этом сайте большинство материалов - техническая литература в помощь предпринимателю. Так же большинство производственного оборудования сегодня не актуально. Уточнить можно по почте: Эл. почта: msd@msd.com.ua

+38 050 512 1194 Александр
- телефон для консультаций и заказов спец.оборудования, дробилок, уловителей, дражираторов, гереторных насосов и инженерных решений.