Краеугольный камень для всех начинающих программистов PHP — организация сайта без использования базы данных. О целесообразности писать не буду. Есть довольно много работающих систем, некоторые очень даже привлекательны. Считается, что проблема «PHP и файлы» давно решена в пользу PHP+MySQL = стандарт. Но эта проблема застыла в вечности, и все равно к этому вопросу обращаются новые адепты и возвращаются те, у кого есть уже опыт программирования на PHP.

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

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

Шутки ради — честно ищем кратчайший список операций для каждого.

Классический способ
1. Открыть браузер.
2. Набрать адрес или нажать на вкладку.
3. Опционально. набрать пароль или нажать подтвердить.
4. Набрать текст.
6. Нажать отправить.

Получаем 5-6 операций. Затраты времени на открытие браузера.

Способ с файлами
1. Открыть блокнот.
2. Набрать текст
3. Сохранить сразу в папку на сервере.

А ведь в этом что-то есть!

3 операции, может, 4. Нет затрат времени на открытие браузера, блокнот в Windows открывается мгновенно.

Про Linux/BSD писать не будем, редактор vi не для контент-менеджера, хотя, если сервер не на рабочем компьютере, то все равно может оказаться быстрее — открыть ssh, создать файл с помощью vim или nano. Тем более, что в vim сохранение и закрытие файла прекрасно сводятся к одной команде. =)

Теперь немного практики. Это лишь начало попытки реализовать идею новостей на файлах. Задача написать максимально простой и понятный код.

Что хотелось бы из функционала?

  • Выводить новость на главной,
  • Перелистывать
  • Добавлять через панель администрирования


Чего не хотелось бы?
  • Использовать функцию scandir или glob.
  • Использовать массивы вообще.

Итак, реализация:

1. Создадим папку в директории www для хранения файлов, у меня bd/.

2. Создадим в bd файл с именем, допустим, all.dat — в нем будем вести счёт новостям. Наличие этого файла избавляет от использования функций scandir или glob для подсчёта файлов. Запишем в него цифру 0.

Панель администрирования
Создадим папку ad в директории www и поместим туда следующий скрипт. У меня index.php. С учётом того, что данная директория будет под паролем и доступна только одному администратору, то тут можно пренебречь некоторыми принципами хорошего кода.

Форма ввода новостей.
<div  align="center">
<form action="index.php" method="post">  
<p>New</p> 
<br/>
<textarea  name="text1" cols="80" rows="25"></textarea>
<p><input name="ok" type="submit" value="send" "/>
<input type="reset" value=reset /></p>  
</form>
</div>


Все просто. Обрабатываем форму. Я делаю минимум условий. Если текстовое поле не пусто, то получаем запись из файла, в котором ведем счет записям — all.dat. А в нем у нас 0.
Создаем файл с именем 0.txt, проверяем на всякий случай его наличие и записываем в него данные.
<?php
$text1=$_POST['text1'];

		if(isset($_POST['ok']) && (!empty($text1)))  {

			$all = file_get_contents('../bd/all.dat');
 $file='../bd/'.$all.'.txt';	

	if (!file_exists($file)) {

		$fp = fopen($file, "w");
	fclose($fp);

	$fp = fopen($file, "r+");
fwrite($fp, $text1);
	
		}				
	}
?>


Теперь проверим, существование нового файла и увеличим счётчик на 1 в файле all.dat.
<?php

$new='../bd/'.$all.'.txt';

	if (file_exists($new))  {

		$all+=1;	
	
		$fp = fopen('../bd/all.dat', "r+");
fwrite($fp, $all);
fclose($fp);
}

?>


Для вывода новостей на главную страницу напишем такой скрипт. Получим число записей из all.dat.
Дальше совсем просто, если переменная для страницы — p — установлена и такой файл есть, получаем содержимое.
Иначе получаем последнюю сделанную запись.
<?php

$p=$_GET['p'];

		$allcount = file_get_contents('bd/all.dat');
		$entry="bd/{$p}.txt";	

		if (isset($p)  && file_exists($entry)) {	
 	$news=file_get_contents($entry); 
		
}
 
else {
			
	$p=$allcount-1;
	$entry="bd/{$p}.txt";	
	$news=file_get_contents($entry); 	
	
}

?>
<div class="bform"><div class="headlines"><?=$news?></div></div>
<div class="footer ">
<a href="index.php">First</a> |
<a href="index.php?p=<?=--$p?>">Next</a> </div>


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

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

Файлы можно хранить не в .txt а .html, что позволит прописывать для каждого файла, например, свои мета-теги.
Несложно будет добавить эту опцию в панель администратора.

Post Scriptum:
Целью этой заметки является привлечение внимания к перегруженности профессиональных решений для организаций новостей и поиска вдохновения для написания микродвижков.

Ссылка для вдохновения: пример работы и ссылка на точную копию

Дополнение: на базе этого скрипта можно попробовать реализовать автоматический текстовый слайдер. При этом можно использовать ajax, я использую псевдо-аякс в примере ниже и немного анимации (CSS3).
Рекомендуется открыть в Opera или Chrome: Link

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

Комментарии (27)


  1. ActioNk
    17.04.2015 10:53
    +15

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


  1. LionAlex
    17.04.2015 10:55
    +6

    Задача написать максимально простой и понятный код.

    Когда стоит такая задача, не стоит использовать переменные с именами $files1, $a.

    $files1=array_reverse($files1);

    scandir() позволяет задать сортировку вторым параметром и избавиться от этой строки.

    scandif($dir, 1)
    

    для PHP версии < 5.4 и

    scandif($dir, SCANDIR_SORT_DESCENDING)
    

    для 5.4 и выше.

    И вообще, вместо scandir можно использовать glob("*.txt") и тогда не понадобится $p == $all-2 и preg_match('/\d+\.txt/', $val), правда array_reverse придется оставить


    1. dcc0 Автор
      21.04.2015 22:00

      Пробовал потом и с glob в итоге выбросил и то, и другой.


  1. Pinsky
    17.04.2015 11:02
    +21

    Параолимпийские игры по программированию.


    1. LionAlex
      17.04.2015 11:15
      +1

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


      1. maxru
        17.04.2015 12:10
        +1

        Для этого есть тостер и phpclub с Фанатом.


        1. zelenin
          17.04.2015 12:33
          +1

          для этого есть тостер с фанатом и phpclub с фанатом — он вездесущ )


          1. maxru
            21.04.2015 12:26

            внезапно


  1. ApeCoder
    17.04.2015 11:10
    +4

    Классический способ
    1. Открыть браузер.
    2. Набрать адрес или нажать на вкладку.
    3. Опционально. набрать пароль или нажать подтвердить.
    4. Набрать текст.
    6. Нажать отправить.

    Получаем 5-6 операций. Затраты времени на открытие браузера.

    Способ с файлами
    1. Открыть блокнот.
    2. Набрать текст
    3. Сохранить сразу в папку на сервере.


    Для «сохранения сразу на сервере» не надо ли набрать адрес этого сервера и пароль?


    1. dcc0 Автор
      22.04.2015 04:02

      Можно убрать из этой строчке «на сервере» и станет понятно и вопрос отпадет сам-собой.
      Если сервер на рабочем компьютере, то набирать не надо адрес.


      1. ApeCoder
        22.04.2015 10:56

        Тогда надо не адрес а путь к папке


  1. maxru
    17.04.2015 11:13
    +15


  1. barker
    17.04.2015 11:13
    +15

    Всплакнул, спасибо :')
    Ох уж эти веб-технологии 90-х.


  1. AlexLeonov
    17.04.2015 12:15
    +7

    Что это делает на главной?


    1. Borz
      17.04.2015 12:37
      +9

      собирает минусы


  1. dcc0 Автор
    17.04.2015 13:12
    -5

    Неудобно получилось, только я отправил просьбу по почте, чтобы повременить с публикацией, она состоялась, а я начал ее редактировать :)

    Вчера, после отправки этой заметки через 10 минут пришла мысль в голову, что я поторопился, видимо, пересидел.
    Но я решил все же лечь спать и переделать все утром, а потом написать модераторам.

    Переписал, у брал scandir, хотел сначала glob использовать, потом решил подумать, как вообще выкинуть массивы и циклы.


  1. stell_hawk
    17.04.2015 13:41
    -4

    снимай статью. с ней ты каждые 10 минут минусы получать будешь…
    ЗЫ: уж тогда бы писал в xml и то прок был бы… чуть-чуть


  1. REZ1DENT3
    17.04.2015 14:11

    Файлы можно хранить не в .txt а .html, что позволить прописывать для каждого файла, например, свои мета-теги.
    Несложно будет добавить эту опцию в панель администратора.


    Если вы не хотите использовать все плюшки PDO или MySQLi, SQLite, Firebird, MongoDB… А хотите хранить все данные в файлах, смотрите в сторону json_encode(), json_decode(). Так вы можете хранить данные, хотя бы, в массивах. Если вы хотите сэкономить место на HDD, пакуйте данные gzencode()/gzdecode()… И вам нужно, хотя бы, написать самый тривиальный шаблонизатор на основе str_replace()…

    ЗЫ
    Я не буду говорить на сколько ваш код ужасен и не применим в «нормальной» системе, думаю вы и так уже это знаете.
    Как написал barker, спасибо, что напомнили о веб-сайтах 90х…


  1. dcc0 Автор
    17.04.2015 17:33
    -4

    Вы правы, но я все же попробую объяснить. Есть очень много людей, которые заняты в разработке сайтов — в разной степени, разной сложности. Не спорю, есть уже некие стандарты и профессиональные отточеные решения, в случае с php — их масса.
    Я сам новичок и очень медленно по мере сил вникаю в php, но наблюдаю за форумами и вопросами — они одни и те же.
    «Как сделать пагинатор? Как сделать листалку? Как вывести новости на сайт с mysql? Как вывести на файлах? „
    Фактически — это топ вопросов. На подобные вопросы часто появляется профессиональный ответ и профессиональный код, но в этом отчасти и кроется проблема. Многие, кто работает с готовыми решениями, часто не могут разобраться в профессиональном коде.
    Я честно говоря, сам долго не понимал, с какой вообще стороны подступиться к программированию. Просто читать учебники? Хорошо, но если нет мотива сделать что-то конкретное, прочитанное так и останется в глубинах памяти. Вдобавок в учебниках много теории. А задача, субъективно на пером этапе изучения простая — понять хотя бы механизм, принцип. Я вижу пока только один вариант. 1. иметь мотив сделать что-то конкретное — пусть — это велосипед. 2. найти максимально простой пример, самый простой код, желательно, условно говоря, с псевдокодом на русском языке.
    Часто наблюдая за развитием тем на форумах, видел, что многих отпугивает объем кода в профессиональных решениях. А как объяснить механизм? Опять же, субъективно, только самым простейшим решением. И такое решение, в случае со стандартными вопросами php — однозначно может вызвать негодование или усмешку профессионала. Но не реальное, практическое использование примера является задачей — “это лишь начало попытки реализовать идею новостей на файлах».

    REZ1DENT3, спасибо за советы по json_encode(), json_decode(). Пока для реальных задач хватает Mysql.


  1. dcc0 Автор
    17.04.2015 20:31
    -3

    Ладно, вдруг все же кому-то пригодится и у кого-то появится идея сделать что-то существенное, но простенькое.
    Для тестирования чуток допиленное в архив:
    https://yadi.sk/d/a1An-QyHg4prH


  1. lolipop
    17.04.2015 20:32
    -3

    Я просто оставлю это здесь:
    blog.getpelican.com


    1. dcc0 Автор
      17.04.2015 20:41
      -3

      lolipop, спасибо…


      1. BupycNet
        17.04.2015 22:02
        -2

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


  1. dcc0 Автор
    17.04.2015 22:19

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

    Но интересно было сделать что-то совсем микро, и обязательно без бд. Я еще буду экспериментировать с этим.
    Тут немного истории, я начал писать микро-движок с mysql для мобильного (Android) веб-сервера — Palapa web server (PHP+MYSQL+MSMTP) — сервер можно бесплатно скачать на Google Play Market. Вот тут-то и всплыли идеи из прошлого, на тему микродвижков.
    Если интересно можете ознакомиться с моей же темой на http://4pda.ru/forum/index.php?showtopic=583136


  1. akubintsev
    18.04.2015 10:11
    +3

    И зачем люди годами вырабатывают лучшие практики? Не, мы сами с усами.


  1. t1gor
    30.04.2015 01:38

    Ну уж если так хотелось не использовать массивы и scandir, почему было бы не использовать RecursiveDirectoryIterator?


    1. Pinsky
      30.04.2015 10:39

      его нужно знать для этого)