От автора: Данный урок является логическим продолжением урока "Как сделать FAQ на сайте с использованием PHP-MySQL-jQuery". В комментариях к указанному уроку поступила просьба показать, как можно реализовать аналогичную "штуку", но без использования БД, а с использованием в качестве хранилища данных текстовые файлы. Также в комментариях содержалась просьба показать, как создать административную часть, при помощи которой можно было бы управлять указанным хранилищем данных.
Что ж, попробуем реализовать задачу предыдущего урока, используя для хранения информации текстовые файлы. Заодно и научимся основам работы с файлами в PHP, тем более, что пока что на сайте, вроде как, нет информации подобного рода.
Время ролика: 47:22
Сложность: средняя
План урока:
1. Подготовительный этап. Формирование задач (10:24)
2. Читаем файл (13:32)
3. Формирование массива вывода данных (11:14)
4. Выводим данные (11:21)
1. Подготовительный этап. Формирование задач
Прежде всего, давайте попробуем выделить несколько основных плюсов и минусов при использовании файлов в качестве хранилища информации. К плюсам, безусловно, можно отнести простоту использования текстовых файлов. Данные в таких файлах можно создавать и хранить в любой файловой системе. Для них не требуется специализированное программное обеспечение и обрабатывать их можно, наверное, в любом текстовом редакторе. Ну и, конечно же, проект, в котором БД хранятся в текстовых файлах, являются легко переносимыми — их можно без всяких проблем использовать практически на любой компьютерной платформе.
Теперь относительно минусов… Здесь они лучше просматриваются на фоне плюсов при использовании БД. Базы данных позволяют хранить информацию с очень сложной структурой, с разграничением по типам данных. При этом использование БД позволяет существенно упростить поиск, извлечение и редактирование требуемой информации. Чего не скажешь о текстовых файлах — там разработать сложную структуру хранения данных гораздо проблематичнее, а для выполнения операций с требуемой информацией нужно приложить гораздо больше усилий.
Также немаловажным преимуществом БД является поддержка многопользовательского режима. Так, при использовании файлов необходимо помнить о возможности потери информации в случае одновременного редактирования информации в файле (эта вероятность крайне мала, но она все же есть)… в случае с БД такая возможность изначально предотвращена.
Это, на мой взгляд, основные плюсы/минусы использования текстовых файлов. Если Вы больше заинтересуетесь этим теоретическим вопросом, то в сети Вы можете найти целые «баталии» между сторонниками использования файлов и БД.
Ну что ж, продолжим. Для начала возьмем все файлы из предыдущего урока («Как сделать FAQ на сайте с использованием PHP-MySQL-jQuery»), создадим на сервере каталог под наш проект — я назову его «faq_txt» — и скопируем в него файлы предыдущего урока. Теперь откроем в редакторе файл faq.php и внесем в него необходимые правки. Нам не понадобится БД — поэтому код соединения с ней удаляем. Также удаляем код, которым осуществляется вывод информации из БД.
Теперь создадим текстовый файл, который и будет хранилищем информации, т.е. в нем будут храниться пары вопрос-ответ. Файл назовем base.txt и в него поместим 3 пары вопрос-ответ в 3 строки:
1 2 3 |
Шаг 1//Прежде всего необходимо подключиться к серверу БД. Конечно же, у Вас уже должна быть создана БД. Также необходим шаблон, на котором мы и будем проделывать все наши эксперименты. Шаг 2//Здесь Вы должны вытащить из БД все вопросы и необходимые к ним ответы. Также желательно подать их в приемлемом виде, чтобы было понятно, что это именно вопрос-ответ. Шаг 3//На этом этапе необходимо подключить библиотеку jQuery и написать скрипт, которым мы возьмем в набор jQuery все элементы с классом 'question'. Затем при помощи события 'toggle()' мы установим своеобразный переключатель из 2-х функций: по первому клику - показывается ответ на соответствующий вопрос, по второму - ответ скрывается. |
Заметьте, что 1 пара должна занимать ровно 1 строку — эта особенность важна и далее Вы узнаете почему. Кроме того, вопрос и ответ я разделил двумя слешами («//»). На самом деле разделитель может быть и другим, главное, чтобы он не встречался больше в строке, чтобы создаваемая нами программа понимала, что до разделителя идет вопрос, а после него — ответ… ну а с новой строки вновь идет вопрос-ответ и т.д.
Теперь немного о работе с файлами в PHP. Работу с файлами здесь можно разбить на 3 этапа:
открытие файла;
считывание информации или редактирование файла;
закрытие открытого файла.
Перейдем к первому этапу — открытие файла. Сделать это можно при помощи функции fopen(). Ее синтаксис:
1 |
fopen("имя файла", "режим"); |
С именем файла понятно. Теперь к режиму — это режим открытия файла и указывает он на то, для чего именно мы открываем файл: просто прочитать его или записать в него что-то, или дописать информацию в него. Режимов открытия файлов несколько (детальнее об этом можно прочитать в мануале, прилагаемом к дополнительным материалам, или в любом руководстве по PHP), но на практике чаще других используются следующие:
"r" — чтение файла;
"w" — запись в файл, при этом, если в файле уже были какие-то данные, — они будут затерты, т.е. файл будет перезаписан;
"a" — файл открывается для дозаписи, т.е. указатель (курсор) устанавливается в конец файла и новая информация в него дописывается.
Теперь перейдем к написанию кода.
2. Читаем файл
Для того, чтобы нас не отвлекало прочее содержимое файла faq.php, создадим новый файл test.php и будем писать код и экспериментировать в нем, ну а когда код будет готов — просто перенесем его на страницу faq.php.
Итак, откроем файл в режиме чтения:
1 |
$handle = fopen('base.txt', 'r'); |
Результат выполнения функции мы поместили в переменную $handle. Теперь эта переменная является дескриптором открытого файла или, говоря простым языком, — она указывает на открытый файл и именно с ней происходит дальнейшая работа.
Информацию из открытого файла мы будем считывать построчно — именно для этого мы и помещали пару вопрос-ответ в отдельную строку. Считать строку из файла нам поможет функция fgets(). Ее синтаксис:
1 |
fgets(дескриптор файла); |
Но данная функция читает только 1 строку. Для того, чтобы прочитать следующую строку — нам нужно вызвать ее еще один раз и тогда будет считана вторая строка. Для считывания 3-ей строки — необходим повторный вызов функции и т.д. У нас пока только 3 строки, а если таких строк будет 1000… Думаю, Вы уже догадались, что в выполнении неких повторяющихся однотипных действий нам помогут циклы. Единственное, нам нужно сформулировать условие цикла. Таковым будет следующее: считывать строки из файла одну за другой пока таковые есть в файле, т.е. пока не достигнут конец файла.
Считанные строки мы будем, конечно же, помещать не в переменную (переменная ведь предназначена для хранения только 1 значения, а у нас таких значение будет столько же, сколько и считанных строк), мы их будем помещать в массив. Поскольку мы будем работать с массивами, я настоятельно рекомендую Вам ознакомиться со всеми уроками, где затрагивалась эта тема, поскольку без понимания принципов работы с массивами будет сложно понять и всю дальнейшую работу.
Теперь еще раз вернемся к условию. Как можно узнать достигнут ли конец файла? Здесь нам поможет функция feof(), которая проверяет достигнут ли конец файла. Ее синтаксис:
1 |
feof(дескриптор файла); |
Данная функция возвращает значение TRUE (ИСТИНА) если достигнут конец файла или FALSE (ЛОЖЬ) в любом другом случае. Таким образом, в условии мы будем проверять возвращает ли функция ЛОЖЬ, если возвращает — значит конец файла не достигнут и будем считывать строку, если вернет ИСТИНУ, т.е. условие не выполнится — прекратим считвать файл. Код будет таким:
1 2 3 4 5 6 7 |
<?php $handle = fopen('base.txt', 'r'); while(!feof($handle)){ $read[] = fgets($handle); } ?> |
Обратите внимание на восклицательный знак перед вызовом функции feof(), об его использовании в PHP я уже говорил — он обозначает, если перевести на понятный язык, частицу «не». Поскольку в условии мы проверяем возвращает ли функция ЛОЖЬ, мы и указали частичку не, т.е., если прочитать условие — мы получим следующее: «пока(не ИСТИНА){читаем очередную строку}». В данном случае «не ИСТИНА» == ЛОЖЬ.
3. Формирование массива вывода данных
Отлично!
Мы считали файл построчно в массив $read. Теперь каждый элемент массива содержит 1 строку считанного файла. Но нас это не совсем устраивает, поскольку нам нужны вопрос и ответ в разделенном виде. Вспоминаем, именно для этих целей у нас в каждой строке и предусмотрен разделитель. Зная какой именно разделитель использован, а мы знаем это, можно разбить строку в нашем случае на 2 подстроки: в одной будет вопрос, во второй — ответ. Выполнить сформированную задачу нам поможет функция explode(), которая, собственно, и разбивает строку на подстроки.
Ее синтаксис:
1 |
explode("сепаратор", разбиваемая строка); |
В качестве сепаратора указывается разделитель — в нашем случае использовано 2 слеша («//»). Как говорилось, можно использовать и любой другой разделитель — главное, чтобы он не встречался в части строки, которую мы хотим получить в качестве подстроки.
Поскольку на необходимо разбить на подстроки все элементы массива $read — необходимо пройтись по всем элементам массива в цикле. Перебирать элементы цикла будем при помощи цикла foreach(), который и существует специально для обхода элементов массива. Синтаксис оператора foreach():
1 |
foreach(имя массива as переменная){блок действий} |
Здесь мы берем каждый конкретный элемент массива и присваиваем на каждой итерации цикла его значение как раз переменной, указанной после ключевого слова as. Ну а в блоке действий мы уже выполним нужный набор действий с указанной переменной.
Теперь код:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php $handle = fopen('base.txt', 'r'); while(!feof($handle)){ $read[] = fgets($handle); } foreach($read as $item){ $data[] = explode('//', $item); } ?> |
В результате выполнения кода мы получили массив $data, который содержит еще 3 массива (по числу строк), в каждом из которых содержится по 2 элемента (вопрос-ответ). Теперь у нас есть многомерный массив. Осталось вывести его значения. Сделать это можно внутри того же цикла.
4. Выводим данные
Для того, чтобы понять что и как нам необходимо вывести, достаточно распечатать содержимое массива:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php $handle = fopen('base.txt', 'r'); while(!feof($handle)){ $read[] = fgets($handle); } foreach($read as $item){ $data[] = explode('//', $item); } echo '<pre>'; print_r($data); echo ' |
’;
?>
Взглянув на структуру полученного массива, не сложно будет увидеть, что для того, чтобы, к примеру, вывести второй вопрос, мы должны обратиться к индексу 1 массива $data и указать индекс 0 вложенного массива, т.е. так:
1 |
echo $data[1][0]; |
Чтобы вытащить ответ на этот вопрос — обращаемся уже ко второму элементу вложенного массива, т.е. к элементу с ключом 1:
1 |
echo $data[1][1]; |
Теперь, если мы для себя проследим структуру выводимых ключей всех пар вопрос-ответ, то получим следующее:
1 2 3 4 5 6 7 8 |
00 01 10 11 20 21 |
Видим, что вторые цифры в каждой паре чередуются (0 и 1), а первые цифры каждой пары увеличиваются на единицу — от нуля до трех. Соответственно, для вывода в каждой паре первой цифры мы организуем счетчик вне цикла (это будет переменная $i), а в цикле будем увеличивать его на единицу и присваивать его значение первому ключу массива. Ну а вторые цифры мы так и будем выводить — чередуя 0 и 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php $handle = fopen('base.txt', 'r'); while(!feof($handle)){ $read[] = fgets($handle); } $i = 0; foreach($read as $item){ $data[] = explode('//', $item); echo '<div class="question">' .$data[$i][0]. '</div>'; echo '<div class="answer">' .$data[$i][1]. '</div>'; $i++; } fclose($handle); ?> |
Также мы закрыли открытый ранее файл функцией fclose() — здесь ничего сложного нет.
Вот и все…
Осталось перенести итоговый код в то место файла, где мы хотим видеть вывод пар вопрос-ответ — это блок page на странице faq.php. Все работает точно также, как и в предыдущем уроке с использованием БД. Можем в файле на новой строке через разделитель создать еще одну пару вопрос-ответ — она также после сохранения файла и обновления страницы будет выведена на экран.
Итак, наша задача реализована — все не так сложно. В следующем уроке данного цикла мы напишем простенькую административную часть, посредством которой сможем редактировать содержимое файлового хранилища — добавлять, удалять и редактировать имеющуюся информацию. На этом урок окончен.
До новых встреч!
Ваши вопросы и отзывы жду в комментариях
С уважением Андрей Кудлай
Автор: Кудлай Андрей
Редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.
Комментарии (26)