Nickolay.info. PHP. Самая простая CMS или пишем элементарный "движок" на PHP

Заметка родилась как ответ на вопрос одного знакомого. Вопрос был примерно такой:

Мне не нужны сложные программы на PHP, но хочется иметь простейший способ подключения к сайту разных страниц, написанных на обычном HTML. Потому что с разметкой HTML я справлюсь, а вот программированием не владею. Ну и пригодились бы динамическая генерация меню сайта плюс вывод постоянных верха и низа страницы. Всё, что нашёл в Интернете - или огромные громоздкие CMS, которые ставить и настраивать запаришься, или голая теория, в которой без хорошего знания PHP и программирования не разберёшься...

Что ж, эта статья как раз описывает "самую простую в мире" CMS (систему управления динамическим сайтом). Наверное, можно ещё проще, но так как этот мини-"движок" я буду писать прямо сейчас вместе с текстом, то уж как получится...

На сайте уже есть статьи, где можно посмотреть как "заочно" заказать и оплатить хостинг и как закачивать файлы по ftp (там про Perl, но это совершенно неважно), так что на этих моментах я останавливаться не буду, будем считать, что у Вас есть домен и ссылка ftp, по которой Вы можете закачать файлы в корневую папку своего будущего сайта. Кстати, нам подойдут и многие современные бесплатные хостинги, достаточно поддержки PHP 4.3 и выше, а никакие базы данных MySQL для такой элементарной задачи не нужны.

Кроме того, папки на сайте хостера уже обычно настроены так, что "главный файл" index.php отображается автоматически, то есть,

http://www.mysite.com/index.php

означает абсолютно то же самое, что

http://www.mysite.com

Поэтому главный файл нашего движка тоже будет называться index.php

Структура нашего "движка" будет такой:

Сначала напишем config.php, это единственный файл "движка", куда Вам может понадобиться внести свои настройки. Вот он с комментариями (всё, что после символов // до конца строки - это комментарии, они не обрабатываются интерпретаторами PHP), выделенное красным можно менять, естественно, можно добавлять/удалять любое количество записей о файлах сайта в указанном виде.

<?php
 // Название всего сайта, без тегов, желательно, только буквы и цифры
 //Если не нужно, оставьте пустую строку: define ('SITE_TITLE',''); 
 define ('SITE_TITLE','Мой сайт'); 

 //Страницы сайта пишутся так:
 //$pages['имяфайла']='Титул страницы';
 //Все файлы - с расширением .html, скопировать во вложенную папку p
 $pages['index']='Главная&nbsp;страница';
 $pages['first']='Первая&nbsp;страница';
 $pages['second']='Ещё&nbsp;одна&nbsp;страница';
?>

Все апострофы ' имеют значение! Если вдруг Вам понадобился апостроф внутри названия страницы:

Mike's cool site

он пишется так: \'

$pages['index']='Mike\'s cool site';

Кроме того, здесь мы уже сказали, что файл с заголовком Mike's cool site сохранён под именем index.html. В какой папке? В папке p, где будут и все остальные файлы!

Какие хитрости есть в именовании файлов и самих страниц не только для этого скрипта, но и для любого другого?

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

Вашей Windows всё равно, БОЛЬШИЕ или маленькие буквы Вы использовали в названии файла, но почти любому реальному серверу это небезразлично! Осваивайте файловый менеджер Far Manager, там клавишей F11 вызывается меню внешних модулей, где есть команда "преобразование регистра" - она позволяет моментально решить данную проблему.

Во-вторых, русскоязычное имя Вашей страницы будет показано в верхней строке браузера и станет именем закладки на страницу, если кто-то таковую сделает. Поэтому не нужно использовать в титуле страницы всяких сомнительных знаков, вроде <, >, +, ?, !, ', " и т.п. (а вот точку, запятую, дефис - можно), лучше всего, если титулом будет естественный текст вроде "Главная страница" или "Мои программы".

Кроме того, перед названием конкретной страницы удобно дописывать название всего сайта, чтобы в строке заголовка браузера или вкладки получилось что-то вроде "Мой сайт - Главная страница". Эту возможность мы "зашьём" в движок автоматически, а если Вам этого не надо - просто очистите название всего сайта в настройках config.php.

Из этих имён страниц будет составляться меню - и не исключено, что при неудачном стечении обстоятельств название "Главная страница" будет браузером разорвано - слово "Главная" окажется на одной строке экрана, а "страница" - на другой. Чтобы такого не произошло, ставьте в названиях страницы вместо пробелов символы &nbsp; - это так называемый "жёсткий пробел". Я так и сделал.

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

Сам "движок" займёт совсем немного места, причём, большая часть кода уйдёт на всякие проверки корректности и исключения лишнего. Теперь пишем этот движок, то есть, файл index.php:

<?php

function title ($str) { 
 static $title;
 if (!empty($str)) $title=(SITE_TITLE===''?'':SITE_TITLE.' - ').$str;
 return $title;
}

$pages = array();
require_once ("./config.php");

//обработать внешний параметр - имя искомого файла
$p='';
if (isset($_GET['p'])) $p=trim(strip_tags($_GET['p']));
$pk=array_keys($pages);
$pv=array_values($pages);

//найти запрошенный с сайта файл в списке
$file=$pk[0];
$title=$pv[0];
$found=true;
$ind=array_search($p,$pk);
if ($ind) { $file=$pk[$ind]; $title=$pv[$ind]; }
else if (!(empty($p) or $p==$file)) $found=false;

//вывести титул страницы и шапку
title ($title);
include "./header.php";

//сформировать меню
echo '<div align="center">';
foreach ($pages as $key => $val) {
 echo '<nobr>['.($val==$title?'':'<a href="index.php?p='.$key.'">').
 $val.($val==$title?'':'</a>').']</nobr> ';
}
echo '</div>';

//сформировать имя файла
$filename = "./p/$file.html";
if ($found and file_exists($filename)) {
 //получить содержимое тега <body>, если его нет - весь файл
 $file=@file_get_contents ($filename);
 if (!$file) {
  echo ('<p>Фатальная ошибка: на сайте недоступен файл '.$filename.' с данными!</p>'.
   '<p><a href="index.php">Вернуться на страницу скрипта</a></p>');
 }
 if (preg_match("#<body[^>]*>(.*?)<\/body>#msi", $file, $matches)) {
  echo "\n".$matches[1];
 }
 else {
  include "$filename";
 }
}
else {
 echo '<p>К сожалению, запрошенный Вами раздел "'.
  (strlen($p)>50?trim(substr($p,0,50)).'...':$p).
  '" не найден на сайте.<p>
  Воспользуйтесь ссылками на <a href="index.php">главной странице</a> сайтa.</p>';
}
//вывести подвал
include "./footer.php";
?>

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

Обратим внимание на строчки вывода очередного пункта меню -

 echo '<nobr>['.($val==$title?'':'<a href="index.php?p='.$key.'">').
 $val.($val==$title?'':'</a>').']</nobr> ';

- здесь название пункта, в котором мы заменили пробелы на &nbsp;, обрамляется квадратными скобками [ ... ] и заключается в тег <nobr>, который хоть и нестандартен, но во всех популярных браузерах благополучно запрещает разрывать своё содержимое. Разумеется, Вы можете оформить пункты меню иначе, изменив этот код.

Кроме того, такой "сложный" оператор понадобился, чтобы не создавать ссылки на ту страницу, которая сейчас открывается. Если бы мы выводили в меню все подряд ссылки, хватило бы и такого оператора echo:

echo '<nobr>[<a href="index.php?p='.$key.'">'.$val.'</a>]</nobr> ';

Загадочные строчки

if (preg_match("#<body[^>]*>(.*?)<\/body>#msi", $file, $matches)) {
  echo "\n".$matches[1];
 }

просто пытаются с помощью регулярного выражения PHP извлечь из подключённого файла HTML содержимое тега <body>, то есть, Вы можете кидать в папку p и обычные странички, не заботясь о том, чтобы удалить из них "лишние" теги оформления html-файла. Кстати, для этого действия есть готовый метод tidy_get_body, но он появился только в PHP 5. Ну а если содержимого тега <body> найти не удалось, файл со страничкой подключается директивой include.

Написать файлы header.php и footer.php, то есть, "шапку" и "подвал" всех страниц, можно как обычные HTML, я ограничусь простейшим вариантом. Единственный нюанс, который нужно учесть - подключить в файле header.php из тега <title> вывод сформированного нами динамически заголовка окна:

<title><?php echo title(''); ?></title>

Так что получаем вот такой header.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title><?php echo title(''); ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">

<link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>

и простейший footer.php вида

</body></html>

Добавьте по своему вкусу всё, что угодно в шапке и подвале - и получите "дизайн".

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

Вы также можете полностью переписать этот файл style.css по своему вкусу.

body {
 background-color: #fffffd;
 overflow: scroll;
}
table {
 table-layout: fixed;
 border-collapse: collapse;
}
th,td,p { 
 font-family: Verdana, Arial, Helvetica, sans-serif;
 font-size : 12px; 
 line-height: 18px;
}
h3,h4,h5,p,ul,ol,dl,pre,blockquote {
 margin-top: 5px;
 margin-bottom: 5px;
}
td img { display: block; }
a:link,a:active { 
 text-decoration: none; color : #006699; 
}
a:visited {
 text-decoration: none; color : #003399; 
}
a:hover	{ 
 text-decoration: underline; color : #DD6900; 
}

Разумеется, все файлы "движка" нужно скинуть в одну папку - предполагается, что это и есть корневая папка сайта, а в ней создана папка p, в прикреплённом ниже архиве она содержит 3 простейших странички. Я старался не использовать никакого кода, зависящего от настроек или версии PHP, так что, скорее всего, всё заработает - по крайней мере, у меня произошло именно так.

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

 Скачать этот пример в архиве ZIP (4 Кб)

P.S. Конечно же, ничто не мешает переделать по своему вкусу оформление вывода в файле index.php, например, если вам не нравится горизонтальное меню, а хочется вертикального. Вот всё, что изменится:

//сформировать меню
echo '<table align="center" width="90%" cellpadding="4" cellspacing="0" border="1"><tr><td align="center" valign="top" width="200">'; 
  //вместо <div> вставить левую ячейку таблицы (колонку)
foreach ($pages as $key => $val) {
echo '['.($val==$title?'':'<a href="index.php?p='.$key.'">').$val.($val==$title?'':'</a>').']<br>'; 
  //вывести в СТОЛБЕЦ меню
}
echo '</td><td valign="top">';    
 //вместо </div> перейти к правой колонке

//... и далее в этом же файле index.php

echo '</td></tr></table>'; //перед подвалом закрыть таблицу
//вывести подвал
include "./footer.php";

В левую колонку будет выведено меню, а в правую - содержимое. Детали оформления можно поменять, если сделать другую разметку тегами HTML.

Рейтинг@Mail.ru

вверх гостевая; E-mail