Создание сайта. Часть 7: PHP

версия для печати

Полное содержание серии - в конце статьи.

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

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

Небольшое отступление. Зачем вообще изучать PHP в плане сайтостроя? Элементарно, чтобы сделать сайт динамическим. Т.е. не писать в ручную до байта каждую страницу своего творения, а создать программки (скрипты), которые сами будут собирать ответ браузеру. Самый простой пример, на котором я почувствовал необходимость использования PHP: нумерация страниц с контентом (перейдите на главную страницу сайта и посмотрите внизу). Вести такую нумерацию вручную несколько утомительно, а на PHP - 15 строк кода :). Возвращаемся к теме..

Важный момент, упускаемый новичками: PHP-скрипты выполняются на стороне сервера. Поэтому на PHP нельзя выполнить код в браузере посетителя в отличие от JavaScript. PHP-cкрипты так же не знают, дошла страница до бродилки или нет, их дело – только генерировать html-код. А вот если по какой-то причине препроцессор не отработает назначенный скрипт или завершит его с ошибкой, то юзер ничего толкового не получит

С другой стороны, именно из-за серверной стороны действия через ваш дырявый php-скрипт хакер может положить сайт. Поэтому всегда проверяйте в скрипте, что именно получили от пользователя. Нельзя доверять любой входящей информации, будь то переданный логин или загруженная картинка. Как проверять, вы скорее всего узнаете из книг по этой теме. Одна из наиболее удачных - Фленов М. "PHP глазами Хакера" (2005). Сейчас читать ее рано, вернетесь к ней, когда более-менее освоите php-программирование.

Я хочу, чтобы вы понимали, как много у вас свободы выбора в сайтостроении. Писать серверные скрипты на PHP – это не единственный выбор. Есть еще Perl, ASP, Python, Ruby и др. языки, способные собрать страницу для браузера. Просто я их не знаю :-), поэтому говорим только о PHP.

Если будете разворачивать свой веб-сервер с поддержкой PHP, то нужно скачать какую-нибудь сборку с оф.сайта. Их там много, кое-что о выборе версии я писал здесь. PHP без проблем интегрируется в Apache. Нужные настройки спросите у Гугля, по этому вопросу тоже очень много написано.

Я учил PHP по двум книгам сразу, Колисниченко Д.Н. "Самоучитель PHP 5" (2007) и Котеров Д.В. "Самоучитель PHP4" (2001). Вторая книга сильно устарела, но в ней все еще много полезного для начинающего кодера. Читайте их параллельно, иногда сказанное другими словами помогает в понимании материала. Вдобавок очень полезный сайт – php.su. Пошарьтесь, поищите для себя что-то ценное.

На том сайте есть русская справка PHP, кривая и старая. Более новая и полностью рабочая здесь. Вообще можете ознакомиться со всем, что я писал по теме, может будет полезно.

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

PHP работает не только в подчинении веб-сервера и для непосредственного взаимодействия с пользователем может использовать консоль. Этого достаточно, но неудобно, особенно при разработке и отладке именно веб-приложений. Нужен IDE редактор, коего у PHP нет :( Ищем сторонний, желательно со встраеваемым отладчиком. Я перепробовал 6-7 штук разных редакторов, платных и бесплатных, и остановился на Blumentals Rapid PHP, оф.сайт. Программа платная, версия 2010 года была не без косяков, но этот редактор значительно превосходит аналоги по удобству. В нем можно подключить chm-справочник, после чего будет работать контекстная справка. Одной кнопой запускается синтаксическая проверка, есть подсветка кода и предиктивный ввод текста с подсказкой параметров функций.


Все, детство в серии статей закончилось. Далее говорим на полупрофессиональном уровне
Форматирование кода

Если вы никогда ни на чем не программировали, коротко поясню: форматирование - это написание кода в удобочитаемом виде. Используем отступы для каждого вложенного блока, пустые строки и пробелы для разбиения кода на части и т.д. Убодочитаемость - это весьма субъективное понятие. Вот два примера:

Код, созданный года четыре назад, на заре моего web-развития

 ...
$srchlbls=array();//выбранные метки
$lblunion='OR';   //оъединение меток И/ИЛИ
$curlbls='';      //текст меток "выбранные метки"
$d=array();       //Массив под найденные данные. Обязательно его задавать. Если будут критические варнинги, то в шаблон должен уйти хотя бы пустой массив.
$pages=1;
$title=' - Поиск по блогу';
$curlabel=-1;     //Подсветка в меню
//var_dump($_GET);exit;

if (!empty($_GET)){
//Принимаем параметры
	if(isset($_GET['fn'])) $flgFull=$_GET['fn'] AND 1;
	if(isset($_GET['ew'])) $logic=($_GET['ew']==1) ? 'AND' : 'OR';
	if(isset($_GET['lu'])) $lblunion=($_GET['lu']==1) ? 'OR' : 'AND';
	else unset($_GET['lbls']);//если почему-то (читай 'хакерский шмон') не будет указан тип объединения меток, то выбор меток сбрасываем вообще.
	if(isset($_GET['qts'])) $text=$_GET['qts'];//текст из формы быстрого поиска
	else $text=isset($_GET['ts']) ? $_GET['ts'] : '';
	$page=(isset($_GET['page'])) ? max(intval($_GET['page']),1) : 1;
	$per_page=20;             //Количество найденных записей на страницу. Тоже количество, что в шаблоне списка.
	$from=($page-1)*$per_page;
 ...

А это мое видение красиво оформленного кода сейчас

 ...
$srchlbls = array();//выбранные метки
$lblunion = 'OR';   //оъединение меток И/ИЛИ
$curlbls = '';      //текст меток "выбранные метки"

//Массив под найденные данные. Обязательно его задавать. Если будут критические варнинги,
//то в шаблон должен уйти хотя бы пустой массив.
$d = array();

$pages = 1;
$title = ' - Поиск по блогу';
$curlabel = -1;     //Подсветка в меню

//var_dump($_GET);exit; //DBG

if (!empty($_GET)) {

    # Принимаем параметры

	if (isset($_GET['fn'])) {
	    $flgFull = $_GET['fn'] AND 1;
	}

	if (isset($_GET['ew'])) {
	    $logic = ($_GET['ew'] == 1) ? 'AND' : 'OR';
	}

	if (isset($_GET['lu'])) {
	    $lblunion = ($_GET['lu'] == 1) ? 'OR' : 'AND';
	} else {
	//если почему-то (читай 'хакерский шмон') не будет указан тип объединения меток,
	//то выбор меток сбрасываем вообще.
	    unset($_GET['lbls']);
	}

	//текст из формы быстрого поиска
	if(isset($_GET['qts'])) {
	    $text = $_GET['qts'];
	} else {
	    $text = isset($_GET['ts']) ? $_GET['ts'] : '';
	}

	$page = isset($_GET['page']) ? max(intval($_GET['page']), 1) : 1;

	//Количество найденных записей на страницу. Тоже количество, что в шаблоне списка.
	$per_page = 20;
	$from = ($page - 1) * $per_page;
 ...

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

Отладчик XDebug

RapidPHP может работать с отладчиком XDebug. Вообще php-отладчики не привязаны к редакторам, это редакторы понимают только определенные отладчики. В частности XDebug - это сторонняя (3rd party soft) бесплатная программа, debugger+profiler в одной библиотеке. Ставится, как расширение PHP, нужная версия отладчика зависит от установленной версии PHP. Если есть проблемы выбора версии, то сюда скопируйте результат функции phpinfo() (html-код результата), получете инструкции по скачиванию и настройке дебагера. Инфу по теме профайлера ищите на их сайте, в документации где-то.

Установка XDebug. Cкопируйте *.dll в каталог с расширениями PHP - PECL. В php.ini пропишете секцию:

[Zend]
zend_extension="D:\Apache2.2\PHP\PECL\php_xdebug.dll"
xdebug.remote_enable = on

Перезапустите web-сервер и RapidPHP. Теперь ставьте точку прерывания в редакторе, исполнение скрипта будет останавливаться на ней. Просмотр переменных и другой дебаг-инфы: Main menu > View > Debug tools

Альтернативный синтаксис и PHP-теги

Не могу спрогнозировать, когда вы об этом узнаете, но чем раньше, тем лучше. В PHP можно писать блоки условий и циклов в альтернативном синтаксисе. Это очень удобно при вставке php-кода в html-шаблон.

Основной синтаксисАльтернатива
if (condition) {statments0} else {statments1}if (condition): statments0; else: statments1; endif;
for|foreach (condition) {statments} for|foreach (condition):
...
statments;
...
endfor|endforeach;
<?php echo 'something';?><?='something';?>

Пример использования:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=windows-1251'>
</head>
<body>
<? if ($warning): ?><div class='warn'><?=$warning?></div>
<? else: ?>
  <? foreach ($data as $v): ?>
      <span class='post'>Номер записи <?=$v['id']?></span>
      <p>Куча всякого текста для примера. В часности данные генератора:<?=$v['text']?></p>
    <? endforeach ?>
<? endif ?>
</body>
</html>

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

.. существует четыре набора тегов, которые могут быть использованы для обозначения PHP-кода. Из них только два, - <?php ... ?> и <script language="php"> ... </script>, всегда доступны. Другими двумя являются короткие теги <? ... ?> и теги в стиле ASP <% ... %>, которые управляются в конфигурационном файле php.ini параметрами short_open_tag и asp_tags соответственно.

Важное замечание. Если в настройках PHP запрещены короткие теги (short_open_tag = false), тогда такие вставки будут проигнорированы, т.е. пойдут простым текстом. Но! Вставка типа <?=$someVar?> при этом все равно будет работать. А все потому, что такая запись - это сокращение, а не короткие теги. Т.е. при парсинге она превращается в <?php echo $someVar ?> и работает независимо от разрешения коротких тегов.

Cron

Crontab (aka Cron) – это линуксовый планировщик. Применительно к сайтострою его удобно использовать для запуска служебных скриптов по таймеру. Например, раз в неделю проводить очистку БД пользователей, или раз в сутки парсить чужой сайт на предмет новостей ;) Скрипты для Cron необязательно писать на PHP, пойдет любой скиптовый язык (bash, perl, python и т.д.).

Чтобы постичь все тонкости Crontab, нужно переехать на Linux =-) Я расскажу только об одной проблеме, возникшей у меня с этим планировщиком. Поскольку у меня на localhost стоит Windows, то окончания строк в моих скриптах были виндовские – \r\n. Поэтому Cron хостера игнорировал мои указания к действию, описанные в скрипте.

Потратив много часов на тесты и переписку с поддержкой, мы в итоге разобрались, что к чему. Итак, в ваших скриптах для Cron должны быть линусковые окончания – \n. Первой строкой таких скриптов добавляйте директиву "#!/usr/bin/php". Это указание планировщику, каким обработчиком разбирать скрипт. Естественно, путь и обработчик могут быть другими, это только пример. Если дополнительно требуются какие-то ключи в директиве, то об этом можно узнать на конкретном хостинге.

Практика

Если будете сохранять php-скрипты в кодировке UTF-8, тогда обязательно указывайте без BOM, иначе наступите на грабли. Если в файле будут присутствовать эти самые 3 байта порядка, тогда при загрузке скрипта они сразу передаются в ответ браузеру. При этом уже нельзя работать с header/session/cookie в PHP, будет ошибка "Cannot modify header information ... (output started at script.php:1)". Так же, по непроверенным данным, появление этих байтиков перед DOCTYPE влечет к разрыву шаблона под IE и глюкам в других бродилках.

[UPD] "Eсть и другие миры" кроме Windows и поэтому я вам настоятельно рекомендую писать сайт именно в кодировке UTF-8. Это касается любых файлов и базы данных (если будете ее использовать). Например, редакторы под Linux работают с UTF-8 из коробки, и бывает очень сложно включить в них поддержку win-1251. Возможно вы никогда не пересядете на другую ОС или редактор, но лучше подготовиться заранее, чем потом придумывать, как все переделать.

Текст в кодировке UTF-8 приводит в увеличению объема файлов, хотя с текущими объемами винтов - не критично. С UTF-8 немного сложнее работать, т.к. текст в мультибайтной кодировке получается переменной длины. Поясню: латинские буквы в нем занимают 1 байт, кириллица - 2 байта, другие языки - до 8 байт. Поэтому в скриптах нужны особые функции и флаги при обработке текстов. Функции есть, просто нужно вовремя вспоминать про их использование. Все эти минусы - ерунда по сравнении с деревянностью, которую получает сайт в кодировке win-1251 :(

---

Где-то очень далеко от начала в самоучителях вам скажут, что нужно разделять код скриптов и html-страницы. Расскажут, как вставлять данные из скрипта в страницу (кстати, см. пример выше). С этого момента ваши html-страницы станут больше походить на заготовки, шаблоны для заполнения данными. Потом будет мутная глава про библиотекаря. Лично мне кажется неоправданным его использование на небольшом проекте. Главная мысль, которую нужно уловить: "мухи отдельно, котлеты отдельно" =) Я это не сразу постиг, т.к. читал книги от начала. Пришлось переделывать часть проекта. Совсем разделить код скриптов и html-разметку не получится, но этого правила нужно придерживаться.

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

---

Когда-то вы узнаете про GET и POST и начнете путаться, что где использовать. Когда не знаете, что выбрать, придерживайтесть схемы: GET (англ. «получать») для запроса данных у сервера, POST (англ. «посылать») для передачи данных на сервер. Жестких требований нет, это для определенности.

---

Для контроля полученных от юзера данных можно использовать:

  • функции, возвращающие значение заданного типа: intval(), strval() и т.д. (справка PHP, раздел "Функции для работы с переменными")
  • приведение типов (ищите в справочнике раздел "Манипуляции с типами") $var0=(float)$_GET['degree']; //в скобках – явное указание типа
  • регулярные выражения. Например, ожидаем от юзера значение типа "25.4-37.0". Тогда для проверки корректности данных подойдет условие: if (preg_match ('#^([0-9.]+) -([0-9.]+)$#', $_GET['complex'], $match)==0) die ('Неправильный параметр');

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

Так же посмотрите статью о "Супервалидации пользовательских данных ".

---

Не всегда удобно и возможно использовать дебагер. Для просмотра значений переменных можно использовать print_r() или var_dump(). Мне больше нравится вторая функция, она под Windows более читабельную инфу выдает. Пример:

Результат print_r($_GET):
Array ( [rel] => 1 [type] => 10t1t6 [seat] => 152-156 [vol] => 2000 )

Тоже самое, но через var_dump($_GET):
array
  'rel' => string '1' (length=1)
  'type' => string '10t1t6' (length=6)
  'seat' => string '152-156' (length=7)
  'vol' => string '2000' (length=4)

Еще один вариант, var_export(). Использую ее, когда нельзя получить данные в браузер, не нарушив при этом работу скрипта. Например, ajax-запрос или обращение c другого сервера. Пример использования:

file_put_contents('d:\debug.log', var_export($someVar, true), FILE_APPEND);

В результате в файле debug.log окажется содержимое переменной $someVar.

---

Если PHP запущен на nix-сервере, то могут быть загадочные глюки с кириллицей в некоторых функциях. Глюки были замечены с preg-* функциями и, как следствие, fgetcsv(). В первом случае у меня шаблон типа "#(\w)+#" не видел русские буквы. А парсер csv-файлов, работающий на fgetcsv(), разбирал не весь русский текст. Я не знаю точно, откуда "ноги растут", лечится трабла явным определением локали в скрипте, использующем эти функции с русскими текстами:

setlocale(LC_ALL, 'ru_RU.CP1251', 'rus_RUS.CP1251', 'Russian_Russia.1251');

Кодировка может быть другая, но суть та же.

---

PHP (как и JavaScript) поддерживает следующий синтакис цикла for:

for ($i=0, $arr_cnt=count($arr); $i<$arr_cnt; $i++)

такая запись по времени выполняется быстрее, чем:

for ($i=0; $i<count($arr); $i++)

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

---

Для передачи значений переменных из PHP в JavaScript можно использовать cookies, явные вставки в шаблон документа или аттрибуты HTML-тегов. Про печеньки нечего рассказывать, все просто. Поясню про вставку:

<!--какой-то html шаблон -->
....
<script type="text/javascript">
  var recid=<?=$id?>;
   var golast=<?=$golast?>
</script>
<script type="text/javascript" src="script.js"></script>
...

В шаблоне инициализируются глобальные js-переменные recid и golast, которые в потом будут использоваться в подключаемом script.js. Прошу не кидаться булыжниками, в свое время такой подход мне виделся приемлемым. С тех пор я стал немного умнее :)

Похожий, но более правильный способ передачи переменных реализуется через аттрибуты:

<div id="cmntWrapper" data-golast="<?=$golast?>"' data-recid="<?=$id?>">
...
</div>
<script type="text/javascript" src="script.js"></script>

Здесь тегу div#cmntWrapper назначаются два аттрибута, data-golast и data-recid. В подключаемом скрипте получить эти аттрибуты можно так:

var obj=document.getElementById('cmntWrapper');
var golast=obj.getAttribute('data-golast');
var recid=Number(obj.getAttribute('data-recid'));

Здесь есть хорошая статья по теме использования аттрибутов в JavaScript, рекомендую почитать.

[1oo%, EoF]
Остальные статьи серии:
1. Идея
2. Работаем над дизайном
3. HTML, CSS
4. Как работает интернет
5. Apache
6. JavaScript
7. PHP
8. MySQL
9. cookie и сессии
10. mod_rewrite

Понравилась статья? Расскажите о ней друзьям:


Комментарии
Для работы модуля комментариев включите javaScript


Показать/скрыть правила
Имя
[i] [b] [u] [s] [url]
:-) ;-) :D *lol* 8-) :-* :-| :-( *cry* :o :-? *unsure* *oops* :-x *shocked* *zzz* :P *evil*

Осталось 1000 символов.
Код защиты от спама Обновить код
Каждый комментарий проходит ручную модерацию. 100% фильтрация спама.
Продвижение
Время
Метки