Содержание раздела "Кодинг":
Семь основных ошибок PHP программиста
Модульное программирование на PHP или как написать маленький портал
Маленькая баннерная сеть каждому
Сделать сайт в оффлайне, от и до? Реально!
Установка Apache
Подпишитесь на рассылку от ведущего раздела "Кодинг"
Семь основных ошибок PHP программиста
Целевая аудитория
Эта серия статей предназначена для тех программистов на языке PHP, которые хотят избежать наиболее общих ошибок в написании кода. Читатель, как минимум, должен знать общий синтаксис PHP, а также весьма желателен некоторый опыт использования языка на практике.
Введение
Одна из наиболее сильных сторон PHP является, одновременно, и его слабой стороной: PHP очень прост в изучении. Это привлекает многих людей; однако, несмотря на его кажущуюся простоту, не так-то просто научиться использовать этот язык правильно и эффективно.
Как правило, дело в недостаточной практике программирования. Неопытные программисты становятся перед лицом необходимости создания сложных веб-приложений. Поэтому сплошь и рядом допускаются ошибки, которых избежал бы опытный программист, такие как необоснованное использование функции printf()или неправильное использование семантики PHP.
В этой серии из трех статей представлены наиболее, по нашему мнению, характерные ошибки. Эти ошибки можно классифицировать по нескольким категориям, от "некритических" до "смертельных". Наряду с анализом этих ошибок, представлены способы их избежания, а также некоторые "маленькие хитрости", накопленные за многие годы практики программирования.
Часть 1: Описываются 7 "детских" ошибок (#21-15, в обратном порядке, в соответствии со степенью серьёзности по нашей классификации). Такие ошибки не вызывают серьёзных проблем, но приводят к уменьшению эффективности работы программы, а также выражаются в громоздком трудночитаемом коде, в который, к тому же, трудно вносить изменения.
Часть 2: Следующие 7 ошибок (#14-8) относятся к "серьёзным". Они ведут к ещё более значительному уменьшению скорости выполнения кода, уменьшению безопасности скриптов; код становится еще более запутанным.
Часть 3: Описания семи, последних, "смертельных" ошибок. Эти ошибки концептуальны по своей природе и являются причиной появления ошибок, описанных в 1-ой и 2-ой частях статьи. Они включают и такие ошибки, как недостаточное внимание, уделённое как проекту в целом, так и коду программы, в частности.
14. ПРЕНЕБРЕЖЕНИЕ ПРАВИЛАМИ ПРИСВОЕНИЯ ИМЁН
Одна из наиболее серьёзных ошибок программиста - непродуманная система именования переменных проекта. Нередко приходится тратить уйму времени на разбор кода только потому, что автор вдруг решил ввести в программу переменные $fred и $barney вместо ожидаемых $email и $name. Речь ведётся о реальном проекте, где не менее реальный программист решил все переменные проекта назвать именами героев мультсериала "Flinstones" (Это не шутка). То как вы назовёте переменные и функции программы, определит во многом читаемость её кода. Наиболее распространёнными ошибками являются имена:
- слишком короткие или наоборот, чрезмерно длинные;
- не связанные по смыслу с контекстом программы;
- не учитывающие регистрозависимость;
- замедляющие разбор и чтение кода (особенно это касается имён функций).
Именование переменных
Регистрозависимость
В PHP имена переменных регистрозависимы, то есть $user и $User - две записи в списке переменных скрипта. Однако некоторые программисты активно пользуются этим и производят на свет переменные с совершенно одинаковыми именами, но использующими буквы разных регистров. Это отвратительная привычка. Регистр букв никогда не должен быть единственным отличием двух переменных. Каждая переменная на своём поле действия должна иметь уникальное имя.
Слишком короткие имена
Для обозначения переменных многие программисты используют одним им понятные аббревиатуры. О чём впоследствии сильно жалеют, ибо смысл сокращения затерялся во времени своего создания. Имя переменной должно отражать характер её значения, то есть содержания и обозначаться полными словами или общепонятными сокращениями.
Слишком длинные имена
С другой стороны, наблюдаются случаи злоупотребления длинными именами. Наиболее общее правило: имя переменной должно состоять максимум из двух слов. Разделить эти два слова мы можем, поставив understrike (то есть "_") или написав второе слово с заглавной буквы.
Пример #1. Положительный.
Как правильно присваивать имена переменным:
$username = 'sterling';
$password = 'secret';
$teachers = array ('Sadlon',
'Lane',
'Patterson',
'Perry',
'Sandler',
'Mendick',
'Zung');
foreach ($teachers as $teacher);
Пример #2. Отрицательный.
Теперь рассмотрим несколько преувеличенные примеры того, как не следует присваивать имена переменным:
$username_for_database = 'sterling';
$guMbi = 'secret'; // for the $password
$thelastnamesofteachers = array ('Sadlon',
'Lane',
'Patterson',
'Perry',
'Sandler',
'Mendick',
'Zung');
foreach ($thelastnamesofteachers as
$TeaChER);
Имена функций
Все правила, применяемые для имён переменных, годятся и для функций. Однако в случае с функциями, грамматические реалии имеют большее значение.
Помните, что в PHP все функции, встроенные или определённые разработчиком, - регистронезависимы.
Использование глаголов
Функции в PHP можно сравнить с какими-либо действиями, совершаемыми в реальном мире. Таким образом, имена функций должны отражать эту направленность на действие, то есть выражаться глаголами. Причём лучше в настоящем времени.
В качестве примера рассмотрим функцию, генерирующую Гауссовы случайные числа. Предполагается, что из её имени мы должны понять, какая именно формула используется в генерации числа. Вот так: generate_gaussian_rand().
Обратите внимание на использование глагола в имени функции. Именно глагол помещает функцию в правильный контекст:
<?php
list ($num1, $num2) = generate_gaussian_rand();
list ($num3, $num4) = generate_gaussian_rand();
?>
Для сравнения, другой пример:
<?php
list ($num1, $num2) = gaussian_rand_generator();
list ($num1, $num2) = gaussian_rand_generator();
?>
Видите разницу? Во втором примере для обозначения действия использовано существительное. И если назначение функции ещё прослеживается, название затрудняет чтение кода.
Мораль: используйте глаголы!
13. НЕПРОДУМАННАЯ РАБОТА С ДАННЫМИ: БД И SQL
Забавно иногда наблюдать, сколько разных уловок находят люди для организации доступа к базам данных и получения выборки результатов. Среди прочих особенно выделяются комбинации из веток if, циклов do..while, множественных запросов и вызовов функции sql_result() внутри цикла for. Чем, на их взгляд, они занимаются? Код, основанный на методе научного тыка, говорит о недостаточно ясно определённой организации работы с БД. Те, кто прилагают все свои усилия на написание кода, а не на написание правильного кода, рискуют больше потерять, чем заработать. Некорректная выборка данных - яркий тому пример. Некоторые программисты не уделяют достаточно времени на тщательное продумывание этого момента. Естественно, в реальной жизни может и не оказаться того "единственно верного" способа выборки данных, но всегда найдётся тысяча "неверных", это точно. Ошибки в организации выборки данным можно разделить на три класса:
- неправильное использование функций обращения к БД
- ошибки SQL: запрашивается не то, что нужно
- обработка результатов выборки средствами PHP
Неправильное использование функций обращения к БД
Один из PHP-исходников предлагал следующий способ получения выборки из БД (приведённый ниже код в проекте находится после сгенерированных SQL-запросов):
if (!($row = sql_fetch_row ($result))) {
print "Ошибка: не найдено ни одного ряда";
exit;
}
do {
print "$row[0]: $row[1]\n \n";
}
while ($row = sql_fetch_row ($result));
Примечание: в данном и последующих примерах $result является дескриптором выборки или указателем на неё. Другими словами, был произведён запрос и получено определённое множество рядов. Примеры демонстрируют методы эффективной обработки этого множества. В этом отрезке кода есть две ошибки: проверка на "ноль рядов" - это попытка получить хотя бы один. полученные данные не хранятся в ассоциативном массиве.
Проверка на "ноль рядов" ($result): неправильный подход
Задействовав функцию sql_fetch_row(), данный кусок кода предлагает косвенную проверку выборки на наличие хотя бы одного ряда данных. Но ведь существует прямой способ - это подсчёт количества рядов в выборке $result функцией sql_num_rows(), как показано ниже:
<?php
if (sql_num_rows ($result) <= 0) {
print " Ошибка: не найдено ни одного ряда";
exit;
}
while ($row = sql_fetch_row ($result)){
print "$row[0]: $row[1]\n \n";
}
?>
Избавляемся от do..while
Прежде всего, исчезает необходимость в использовании давно уже поднадоевшего do..while, ибо для проверки на "ноль рядов" функция sql_num_row() не выдёргивает первый рядв $row, и указатель по-прежнему установлен на начало.
В PHP Source как-то был представлен подобный фрагмент кода. Если выборка не была нулевой, то функция sql_fetch_row() внутри условного блока доставляла первый ряд. Для получения остальных приходилось прибегать к do..while, потому что получение ряда из выборки ("to fetch" - принести, доставить// Прим. перев.) смещает указатель в ней. Таким образом, сначала вам придётся обработать уже полученный ряд ("do"), только потом получить второй ряд и так далее.
Так чем же do..while так провинился?
- в данном примере внутри цикла do..while помещён только один оператор: простой вывод. Теперь представим, что там может оказаться не один, а десять операторов. Тогда редактору кода придётся искать условие while после оператора do и целого блока действий внутри цикла. Занятие не из приятных.
- условие while обычно располагается в начале блока, а не в конце его. Поэтому редактору кода нужно будет уделять этому особое внимание при чтении, чтобы не спутать цикл do..while с предварительным условием while обычного цикла.
Делаем всё просто и понятно
В случае получения нулевой выборки, функция sql_num_row() в отличие от sql_fetch_row() делает именно то, что вам нужно сделать:
- действие sql_fetch_row(): "При попытке получить первый ряд не найдено ни одного ряда. Это может
- означать, что в данной выборке их нет".
- Действие sql_num_row(): "Количество рядов в выборке равно нулю".
Но как это отражается на написании кода?
Рассмотрим следующий пример, где операторы внутри условия записаны псевдокодом:
- if(!($row = sql_fetch_row($result))){Print Error}:
- Получаем первый ряд из выборки.
- Если выборка пустая, то переменной $row приписываем 0; ноль логически выражается False; отсюда
- !(0)=True; выводим сообщение об ошибке.
- Иначе, если выборка не пустая, получаем первый ряд, приписываем его переменной $row; $row не равно
- нулю, то есть True; !(True)=False; выходим на цикл do..while.
- If(sql_num_rows($result)<=0){Print Error}:
- Подсчёт рядов в выборке.
- Если их меньше или равно нулю, выводим сообщение об ошибке.
- Иначе - идём дальше.
Итак, какое из двух выражений проще и быстрее понять? Безусловно, подсчёт рядов - более прямой и короткий путь.
Каково всё же практическое преимущество второго способа? Невелика разница, что мы поместим внутри этого условия - многого тут не выиграть.
Однако на протяжении 10 000 строк вашего кода продуманные, а потому просто и ясно изложенные идеи сэкономят кучу времени редактору кода (вот и первое преимущество). Есть и другие преимущества: разработка скриптов заметно ускоряется и становится более размеренной.
Если ваша СУБД не поддерживает sql_num_row()
Действительно, некоторые СУБД могут не поддерживать эту функцию. Отнесёмся с сочувствием ко всем владельцам таких систем. Им придётся проверять выборки "на ноль рядов" путем запроса первого ряда. Однако и здесь, рекомендуем использовать булевские переменные:
<?php
$found = false;
while ($row = sql_fetch_array($result)){
$found = true;
}
if (!$found){
print "Ошибка";
}
?>
Получение рядов данных: правила эффективной работы
Вторая проблема нашего кода - это использование функции sql_fetch_row() для получения рядов. Как результат своей работы эта функция возвращает лишь пронумерованный массив. Однако существует ещё и функция sql_fetch_array(), которая возвращает два массива: пронумерованный и ассоциативный:
$row = sql_fetch_array ($result);
print $row[1]; // Второй столбец
print $row[name]; // Столбец name - имя
Примечание: Существуют разные точки зрения на целесообразность использования одинарных кавычек при вставке строковых аргументов. В приведённом примере (столбец name) и далее по статье они не используются.
Какая из функций более удобна для разработчика? Ассоциативные массивы позволяют редактору кода ясно и однозначно понять, какая именно выборка из БД будет осуществляться в каждом конкретном случае. Например:
<?php
if (sql_num_rows ($result) <= 0) {
print "Ошибка: не найдено ни одного ряда";
exit;
}
while ($row = sql_fetch_array ($result)) {
print "$row[name]: $row[phone_number]\n \n";
}
?>
Применение sql_fetch_row($result)
Итак, функция sql_fetch_row() имеет целую тонну недостатков. Однако, существует ситуация, где её можно поставить без всякого ущерба "прозрачности" кода: когда sql-запрос формируется пользователем.
До настоящего момента мы рассматривали примеры с заранее известными запросами и определёнными разработчиком. Но иногда возникает необходимость в запросе, сформированном самим пользователем. В таких случаях разработчику неизвестно количество столбцов в выборке.
Здесь для их эффективной обработки полезно использовать функцию sql_fetch_row() в сочетании с count():
<?php
for ($i = 0; $i < count($row); $i++){
print "Столбец". ($i + 1). $row[$i]. "\n \n";
}
?>
Ошибки SQL: запрашивается не то, что нужно
Практика показывает, что обработка выборки из БД средствами PHP - тоже является ошибкой. Бывали случаи, когда для простого поиска по 2Мб БД программисты использовали PHP, а потом возмущались его медлительностью. А делать выборку "весом" в два метра занимает целую вечность.
Язык Структурированных Запросов (SQL) был специально разработан для запросов и получения данных из таблиц в БД. Идея языка заключается в отсеивании данных ненужных вам (средствами SQL) и получении только тех, которые вам действительно необходимы для дальнейшей обработки (например, средствами PHP).
Если вы заметили, что получаете в выборке данных, больше, чем вам нужно, это верный признак недоработанных SQL-запросов.
Условие WHERE
Классический пример эффективного применения SQL-запросов - использование условия WHERE в синтаксисе SQL.
Рассмотрим пример кода, производящего выборку и выводящего список имён и телефонов всех пользователей с id равным 5:
<?php
//
// В предыдущих строках
// устанавливается соединение, и $conn
// определяется как дескриптор соединения.
$statement = "SELECT name, phone, id FROM samp_table";
$result = @sql_query ($statement, $conn);
if (!$result) {
die (sprintf ("Ошибка [%d]: %s",
sql_errno (), sql_error ()));
}
if (@sql_num_rows ($result) <= 0) {
die ("Получено ноль результатов");
}
while ($row = @sql_fetch_array ($result)){
if ($row[id] & 5) {
print "Имя: $row[name]\n \n";
print "Телефон: $row[phone]\n \n";
break;
}
}
?>
Данный код имеет следующие недоработки: для поиска по всей БД используется PHP; при работе с БД малого размера на это можно и не обращать внимания, но с ростом БД вы обязательно заметите резкое падение скорости работы скриптов.
Выход прост: включите в SQL-запрос условие WHERE:
$statement = "SELECT name, phone FROM samp_table";
$statement .= " WHERE id='5'";
WHERE позволит применить более строгие критерии выборки. Фильтром в данном случае будет являться значение аргумента. В нашем примере это "id=5".
Получив нужную вам выборку, вы используете PHP для простого вывода результатов:
if (@sql_num_rows ($result) != 1) {
die ("Получено неверное количество рядов");
}
$row = @sql_fetch_array ($result);
print "Имя: $row[name]\n \n";
print "Телефон: $row[phone]\n \n";
Обработка результатов выборки средствами PHP
Нередко программист намеренно не сортирует выборку при запросе, перекладывая эту работу на PHP. Такой подход неэффективен, ибо сортировка средствами SQL проходит намного быстрее, чем в PHP.
Для сортировки результатов рекомендуем применять синтаксис SQL (ORDER BY), а не PHP-функцию ksort().
Рассмотрим пример использования ksort() для сортировки выборки по имени (name):
$statement = "SELECT name, email, phone FROM some_table ";
$statement .= "WHERE name IS LIKE '%baggins'";
$result = @sql_db_query ($statement, "samp_db", $conn);
if (!$result) {
die (sprintf ("Ошибка [%d]: %s",
sql_errno (),sql_error ()));
}
while ($row = @sql_fetch_array ($result)){
$matches[ $row[name] ] = array ($row[email],
$row[phone]);
}
ksort ($matches);
Возникает вопрос: а почему бы ни провести сортировку результатов во время выборки? Это избавит нас от необходимости проходить по всему массиву с результатами дважды.
Итак, убираем ksort() и исправляем SQL-запрос, добавив ORDER BY:
$statement = "SELECT name, email, phone FROM some_table ";
$statement .= "WHERE name IS LIKE '%baggins' ORDER BY name";
12. СЛАБАЯ УСТОЙЧИВОСТЬ К ОШИБКАМ
В природе существует огромное количество скриптов абсолютно не справляющихся с пользовательскими ошибками. Своим появлением такие скрипты обязаны программистам, которые не удосуживаются правильно распланировать будущий проект и определить все места возможных ошибок. Причём этим следует заняться до того, как скрипт был написан. Недоработки подобного рода приводят к сбоям программы, что чревато не только получением некорректных результатов, но и падением системы!
Предусмотреть худшее
Любой скрипт может "свалиться" при наступлении каких-либо "критичных" условий. Чтобы свести такой риск к минимуму всегда нужно:
- проверять результаты вызова функций;
- проверять результаты системных вызовов;
- в файле php.ini устанавливать уровень error_reporting на E_ALL.
Проверка результатов вызова функций
При вызове функции, результаты которой подвергаются дальнейшей обработке, обязательно убедитесь, что возвращаемые данные находятся в интервале допустимых значений.
В приведённом ниже примере на шестом витке цикла возникает ошибка "деление на ноль", поскольку $i наращивается на 1, а $j уменьшается на 1. На шестом проходе $i=$j=1.
<?php
mt_srand((double)microtime() * 10000000);
function do_math ($a, $b)
{
return (($a - $b) * 2) / mt_rand();
}
for ($i = 5, $j = -5; $i > -5; $i--, $j++){
print $j / do_math ($i, $j) . "\n";
}
?>
Проверка результатов системных вызовов
При обращении к внешним файлам или процессам всегда проверяйте, всё ли работает корректно.
Блестящий тому пример - проверка ответа системы при вызове функции sql_connect(). Стоит проверить этот ответ и убедиться, что подключение к БД действительно имело место. Если этого не сделать, то все запросы к БД могут не состояться, а некоторые данные могут быть утеряны; вы же будете пребывать в счастливом неведении.
$conn = @sql_connect ($host, $user, $pass);
if (!$conn) {
die (sprintf ("Ошибка [%d]: %s",
sql_errno (), sql_error ()));
}
Установка уровня error_reporting в файле php.ini на E_ALL
Убедитесь, что PHP правильно сконфигурирован, то есть уровень error_reporting (отображение сообщений об ошибках) выставлено на наивысший уровень. При другой конфигурации, по крайней мере, на время отладки скриптов, многие ошибки типа "неверное регулярное выражение", "недопустимое значение" ускользнут от вашего внимания.
Обратимся ещё раз к примеру, приведённому в части "Проверка результатов вызова функций". Предположим, что error_reporting выставлен не на максимум, а, скажем, на E_ERROR.
Обратите внимание на то, как скрипт выполняет функцию do_math, но не сообщает об ошибке "деление на ноль", которая, однако, имела место (при $i=$j=0 вывода результата просто не было).
<?php
error_reporting (E_ERROR);
mt_srand ((double)microtime() * 1000000);
function do_math ($a, $b)
{
return (($a - $b) * 2) / mt_rand();
}
for ($i = 5, $j = -5; $i > -5; $i--, $j++){
print $j / do_math ($i, $j) . "\n";
}
?>
Результат работы скрипта:
-5148.25
-5271
-323.75
-4931
-7713.5
-4702.5
-488.5
-928.5
-1394.75
Свои обработчики ошибок
Как правило, PHP выдаёт сообщения об ошибках непосредственно в браузер и не позволяет разработчику подавить или перехватить их. Однако в PHP4 у вас появилась возможность перехвата таких сообщений с помощью функции set_error_handler().
Функция set_error_handler() применяется для записи ошибок вашего скрипта. Теперь вы можете перехватывать все ошибки и программировать собственные обработчики - warning'и пользователей больше не побеспокоят.
В следующем примере set_error_handler() назначает обработчиком по умолчанию функцию error_handler(). В \случае возникновения ошибки вызывается error_handler(), и встроенная функция error_log() регистрирует сбой в файле лога error_file.
Если происходит ошибка класса E_ERROR, работа скрипта прекращается и выводится сообщение об ошибке.
<?php
// void error_handler(string type, string message, string file, int line)
// Индивидуальный обработчик ошибок, определён функцией
// set_error_handler()
//
function error_handler ($type,
$message,
$file=__FILE__,
$line=__LINE__)
{
error_log("$message, $file, $line", 3, 'error_file');
if ($type & E_ERROR) {
print 'Произошла ошибка,
зарегистирована.';
exit;
}
}
set_error_handler('error_handler');
?>
11. НЕОПРАВДАННОЕ ИСПОЛЬЗОВАНИЕ ООП
Парадигма ООП - замечательный подход к написанию кода. У ООП есть множество неоспоримых преимуществ, самое значительное из которых - возможность использовать заново уже некогда написанный код. Однако все мы рано или поздно осознаём тот факт, что 'PHP - не объектно-ориентированный язык'.
Несмотря на то, что PHP имеет корректно работающую поддержку объектов, использовать объекты там, где можно без них обойтись - недальновидно и неэффективно. Причина? Дело в том, что поддержка парадигмы ООП в PHP реализована не в полном объёме.
Несмотря на присутствие основных элементов, PHP всё-таки не хватает многих "продвинутых" функций (как защищённые члены или закрытые переменные), которые обязательны для "настоящих" объектно-ориентированных языков (например, Java, C++).
Кроме того, поддержка объектов в PHP недостаточно отработана и не очень эффективна. Это означает, что использование парадигмы ООП может существенно снизить скорость выполнения программы.
Примечание: Другими словами, скрипт, работающий на объектах будет исполняться медленнее, как код внутри eval() по сравнению с обычным кодом. Для более наглядных примеров, где использование ООП принимает какие-то уродливые формы, пришлось бы прибегнуть к продвинутым функциям концепциям PHP, некоторые из которых даже незадокументированы. Так что остановимся на этом.
А что же мы сможем без ООП?
Если вы пришли в PHP из Java или C++, где без объектов трудно создать что-либо более или менее серьёзное, то и в PHP вам будет трудно обходиться без них. Но будьте уверены, что серьёзные приложения могут быть написаны и методик и приёмов ООП (PHP был написан на C, а последний, как мы знаем, не поддерживает объектов).
Итак, для тех, кто не привык обходиться без ООП, приведём альтернативные технологии написания связных и расширяемых приложений вне парадигмы ООП:
- Создание API.
- Разработка концепции именования (и работа в её рамках).
- Группирование взаимосвязанных функций в один файл.
Создание API
Соотнесём код программы с тремя уровнями:
- Первый - собственно рабочие функции.
- Второй - API функции. Сюда входят функции для построения конкретного приложения.
- Третий - само приложение:
MortgageRate.php (Ипотечный Кредит):
<?php
// Уровень первый - внутренние функции
// Внутренние функции для расчёта оптимальной
// процентной ставки исходя из времени и
// размера помесячных выплат
function _mort_find_interest_rate ($total)
{
if ($total < 30000)
return (7.4);
elseif ($total > 30000)
return (3.2);
elseif ($total > 50000)
return (2.5);
else
return (1.7);
}
// Уровень второй - API функции
// double calculate_mortgage_rate (int money, int time, int month)
// Рассчитывает процентную ставку исходя из
// суммы займа, времени погашения и интервала
// выплат
function calculate_mortgage_rate ($money, $time, $month)
{
$rate = _mort_find_interest_rate ($money) / 100;
$money /= ($time / $month);
return ($rate * $money) + $money;
}
?>
CalcMortgage.php
<?php
// Третий уровень - приложение
// $money, $time и $period получаем
// из формы
include_once 'MortgageRate.php';
$price = calculate_mortgage_rate ($money, $time, $period);
print "Ваша процентная ставка за $period составляет $price";
?>
Разработка концепции именования и работа в её рамках.
Один из самых неприятных моментов при разработке больших приложений - это конфликты пространства имён. Классы его сегментируют. Таким образом, разные классы могут:
- иметь свойства с одинаковыми именами или
- содержать в себе методы с одинаковыми именами.
Например, класс Phillips и класс Normal могут одновременно содержать метод с именем screwdriver.
В общем, перед началом большого проекта рекомендуется продумать именование для всего, в частности, способы различия глобальных и регулярных переменных, определения библиотечных функций и т. д.
Группирование взаимосвязанных функций в один файл
Связанные API функции лучше всего собрать в один файл так же, как связанные методы объединяются в класс. Такие файлы можно представить классами, где каждая функция представляет собой как бы метод этого класса. Так, каждая функция будет иметь ясное определение и прозрачную структуру.
Например, можно было бы все функции, связанные с общением с БД, собрать в файл DB.php.
ООП, как и всё на свете, хорошо в меру
Небольшая оговорка: эта глава была написана не для того, чтобы отговорить вас от использования ООП вообще. Скорее, это была попытка убедить вас не работать с PHP в режиме Java или C++, где ООП - решение номер один.
Проведите тщательный анализ всех выгод и потерь, прежде чем применить объектный подход в PHP.
10. НЕОПРАВДАННОЕ ИСПОЛЬЗОВАНИЕ РЕГУЛЯРНЫХ ВЫРАЖЕНИЙ
Регулярные выражения - мощный инструмент для поиска и организации данных, как, например, проверка адреса электронной почты на корректность или поиск URL. Но в то же время регулярные выражения работают медленнее других функций PHP, предназначенных для более простых задач.
Например, для перевода целой строки в заглавные буквы, новичок в PHP мог бы написать следующее:
<?php
$URL = "http://www.php.net";
$fp = @fopen ($URL, "r");
if (!$fp) {
die ("Сбой при открытии $URL!");
}
while ($line = @fgets ($fp, 1024)){
$data .= $line;
}
@fclose ($fp)
or warn ("Сбой при закрытии дескриптора $URL");
$data = ereg_replace ("[a-z]", "[A-Z]", $data);
print $data;
?>
Однако, в этом случае, используя тяжеловесный и медленный ereg_replace(), он потратил бы кучу драгоценного времени выполнения на задачу, с которой более лёгкая функция strtoupper() справилась бы намного быстрее $data = strtoupper ($data);
В общем, всегда следует искать более "лёгкую" замену регулярным выражениям, поскольку скорость выполнения вашего скрипта в таких случаях резко возрастает.
Эти функции должен знать каждый
Здесь будут перечислены несколько жизненно необходимых функций, сокращающих время выполнения вашего скрипта:
strtoupper(); strtolower(); ucfirst(); strtr(); str_replace(); trim(); explode(); implode(); substr(); strcmp()
При успешной замене замену регулярного выражения одной из этих функций вы можете рассчитывать на резкое повышение скорости, особенно если анализу подвергаются строки больших размеров.
9. ПРОГРАММИРОВАНИЕ НА PHP КАК НА ДРУГОМ ЯЗЫКЕ
Многие приходят в PHP уже с большим опытом программирования в другом языке, как PERL, C, Java или (ну это ещё куда ни шло) ASP. И частенько "импортируют" техники и подходы, которые не всегда хорошо сочетаются с методиками PHP.
К сожалению, некоторые программисты как-то не удосуживаются поучиться PHP-программированию в стиле именно PHP. Вместо этого они обзаводятся минимальным набором новых для них концепций и "насилуют" PHP.
При таком подходе очень часто на выходе мы получаем медленный и трудно поддерживаемый код. И такие случаи не редкость:
- "однострочники" PERL. PHP - язык мало приспособленный к так называемому методу-"всё в одной строке". Рекомендуем разбивать сложные хитросплетения комбинированных функций и представлять их в более структурированном виде.
Perl
while () {
@_ = split /:/;
$quotes{shift} = shift;
}
print map { "$_: ", reverse split //,$quotes->{$_},"\n";
} keys %quotes;
PHP
<?php
$fp = @fopen('php://stdin', 'r');
if (!$fp) {
die ('Сбой при открытии STDIN');
}
while ($line = @fgets ($fp, 1024)){
list($name, $quote) = explode (':', $line);
$quotes[ $name ] = $quote;
}
foreach ($quotes as $name => $quote){
print "$name: ";
print implode (" ", array_reverse (preg_split ('//',
$quote)));
print "\n";
}
@fclose ($fp);
?>
- Уклонение от встроенных функций: Многие PHP-программисты, пришедшие из C, кажется, не понимают того, что PHP содержит целую армию встроенных функций. Их цель - избавить вас от километровых скриптов. Если вы раньше писали на C, вам настоятельно рекомендуется изучить техническое описание PHP и узнать, какие функции PHP вам может предложить и тем самым облегчить вам жизнь.
- Переименование стандартных функций PHP: некоторые программисты переименовывают стандартные функции PHP только для того, чтобы легче их запоминать. Это не только снижает скорость выполнения скрипта, но и затрудняет чтение кода.
- Неоправданное использование ООП: PHP - не объектно-ориентированный язык, хотя некоторая поддержка объектов всё-таки имеется. И всегда стоит помнить, что использование функций поддержки ООП значительно снижает скорость выполнения скрипта.
8. НЕДОСТАТОЧНОЕ ВНИМАНИЕ К ВОПРОСАМ БЕЗОПАСНОСТИ
Пользователи никогда не будут работать по нашим правилам. Поэтому создание системы устойчивой и терпимой к ошибкам - целиком и полностью ответственность разработчиков, то есть нас.
При разработке приложения вы должны влезть в шкуру обычного юзера. Внимательно изучите все места, где пользовательская ошибка может вскрыть брешь в безопасности. Затем исправьте код так, чтобы программа сама нейтрализовала все ошибки и тем самым избавилась от потенциальных "дыр". Также важно запомнить, что хотя все ошибки и атаки - вина пользователей, за "дыры" или за непроверенные данные на каком-либо уровне отвечаете только вы.
Пример: многие скрипты не используют встроенную PHP-функцию mail(), которая обеспечивает безопасную отправку почты. Вместо этого почта отправляется через программу sendmail с помощью popen(). Это делает код весьма неустойчивым к искажению данных и представляет собой "дыру" в безопасности системы (получателю можно отправить /etc/passwd).
Перечислим наиболее распространённые "дыры", позволяющие искажать данные:
- системные вызовы. Никогда нелишне повторить. Каждый раз нужно убедиться, что пользователь отправляет вам "безопасные" данные для системного вызова. НИКОГДА НЕ ДОВЕРЯЙТЕ ДАННЫМ, ПОЛУЧЕННЫМ ОТ ПОЛЬЗОВАТЕЛЯ. И ПРЕЖДЕ ЧЕМ ПОДСТАВИТЬ ИХ В СИСТЕМНЫЙ ВЫЗОВ ПРОВЕРЬТЕ ИХ.
- регистрация пользователей. Если вы желаете получить корректные результаты, обязательно проверяйте полученные данные, причём, лучше если проверка будет состоять из нескольких этапов. Прежде всего, это проверка адреса электронной почты: убедитесь, что пользователь предоставил вам работающий аккаунт. Кроме того, стоит убедиться, что указанный возраст находится в определённых пределах. Вы можете быть совершенно уверены, что на нашей планете нет двухсотлетних товарищей, которые ещё способны сесть за компьютер.
- приём номеров кредитных карточек. Некоторые программисты ограничиваются самыми простыми алгоритмами; их легко обмануть. Существуют крупные специализированные организации для проверки кредитных карточек; рекомендуем прибегать к их помощи или ресурсам и только потом решать, принята карточка или нет. НИКОГДА НЕ ПОЛАГАЙТЕСЬ ТОЛЬКО НА АЛГОРИТМЫ.
Безопасность системных вызовов.
Если возникает необходимость поместить полученные от пользователя данные в системный вызов, обязательно проверьте и перепроверьте их. Убедитесь, что данные, которые пользователь предоставил системе, не содержат "опасных" элементов и не взломают систему нежелательными командами. Для этого PHP предлагает специальную функцию EscapeShellCmd().
Каждый раз при системном вызове с потенциально небезопасными данными, дезактивируйте их с помощью EscapeShellCmd():
Примечание: дезактивация проходит путём подстановки бэкслэша ("\") перед потенциально небезопасными для системы символами (а именно: #&;?'\"|*?~<>^()[]{}$\\\x0A\xFF).
<html>
<head>
<title>Поиск аккаунта</title>
</head>
<body>
<h1>Поиск аккаунта</h1>
<?php
if ($name) {
system (EscapeShellCmd ("lookup $name"));
print "<b>\n\n";
}
?>
<form action="<?php print $PHP_SELF; ?>" method="GET">
Введите аккаунт для поиска:
<input type="text" name="name">
<input type="submit" value="Найти аккаунт">
</form>
</body>
</html>
Примечание: хотя EscapeShellCmd() - функция чрезвычайно полезная, когда вам нужно убедиться в безопасности полученных данных, всегда стоит проводить специальные проверки в зависимости от вида данных. EscapeShellCmd() не проверит данные на корректность, она лишь предотвратит неавторизованные действия пользователя.
Усиленная проверка данных
Как правило, лучше проверять строку на наличие допустимых символов, нежели на отсутствие недопустимых.
Например, проверить, что переменная $name содержит только буквенные символы. При этом новые пути проникновения в систему имеют меньше шансов просочиться через ваш фильтр.
Проверка адресов электронной почты
Один из самых распространённых видов проверки данных - это валидация адреса электронной почты. Большинство новичков ограничиваются лишь фильтром из регулярных выражений, взятым с какого-нибудь кладбища бесплатных скриптов. Но одних регулярных выражений недостаточно, если вы претендуете на получение действительно корректных результатов. Для большей безопасности вы можете применить ещё парочку методов:
- проверка соединения
- интерактивная проверка
Проверка соединения
Один из способов проверки аккаунта на достоверность без привлечения самого пользователя - это попробовать открыть соединение с сервером, указанным в полученном адресе и проверить наличие аккаунта на данном сервере.
Плюсы
- Никаких действий со стороны пользователя, поскольку операция проводится на программном уровне.
- Выявляет несуществующие адреса, с чем никогда не справится регулярное выражение (например, joe@fgsdh.com).
Минусы
- Выявляются только несуществующие адреса. Например, если John Doe пошлёт e-mail автора этих строк (sterling@php.net), данные будут приняты, несмотря на то, что был предоставлен неверный адрес.
- Данный метод работает медленнее, чем регулярные выражения.
- Почтовый сервер пользователя может временно не работать, при этом рабочий адрес будет восприниматься как некорректный.
Интерактивная проверка
Другой способ проверки - выслать на указанный адрес специальный ключ и попросить пользователя ввести этот ключ, чтобы продолжить процедуру регистрации. Данный метод позволяет проверить не только существование адреса, но и наличие у пользователя права доступа к нему.
Плюсы
- Лучший способ убедиться, что пользователь предоставил корректный и свой адрес (Пользователь должен иметь доступ к аккаунту, указанному при регистрации).
Минусы
- Требуются некоторые действия со стороны пользователя. Это раздражает тех, кто пытается вас одурачить.
- Как и любой другой, этот способ не даёт стопроцентной гарантии надёжности. Пользователь может создать временный аккаунт на Hotmail или Netaddress, а потом дать его при регистрации.
Резюме
В этой статье мы рассмотрели семь "серьёзных" из 21 наиболее общих ошибок PHP-программиста. Итак, вот то, чего следует избегать:
- Пренебрежение правилами присвоения имён: Правильно продуманная система именования переменных и функций проекта даст вам на выходе прозрачный и легко расширяемый код.
- Непродуманная работа с данными: БД и SQL: Некорректно работающая выборка данных говорит о недостаточно ясно определённой организации работы с БД. Да, в реальной жизни может и не оказаться того "единственно верного" способа выборки данных, но всегда найдётся тысяча "неверных".
- Слабая устойчивость к ошибкам: Код должен разрабатываться с нейтрализацией и учётом всех потенциальных ошибок и сбоев. Особенное внимание нужно уделять вызовам функций и системным вызовам.
- Злоупотребление ООП: PHP - язык, где поддержка объектов осуществляется не в полном объёме. Не стоит применять методы ООП также легко, как вы это делаете в Java или C++ (или даже Perl).
- Злоупотребление регулярными выражениями: Регулярные выражения медленно работают. Прежде чем вставить в код регулярное выражение, убедитесь, что более простого и быстрого решения нет.
- Программирование на PHP как на другом языке: Не стоит программировать на PHP как на C или Perl.
- PHP - состоявшийся язык программирования и существует сам по себе. Поэтому, обязательно научитесь программировать именно на PHP, а не так, как это было бы правильно для другого языка.
- Недостаточное внимание к вопросам безопасности: Всегда учитывайте "человеческий фактор". Не вставляйте в системные запросы непроверенные строки данных. Проверяйте адреса электронной почты. Не полагайтесь на алгоритмы при приёме кредитных карточек.
Об авторе
Стерлинг Хьюз (Sterling Hughes) - независимый разработчик веб-сайтов, занимается созданием динамических веб-приложений для некоторых крупнейших мировых компаний. Участвовал в создании cURL and SWF расширений PHP с открытым исходным кодом. Его книга, "Настольная книга программиста PHP" (The PHP Developer's Cookbook), была издана в октябре 2000 года издательством "Sams publishing".
Модульное программирование на PHP или как написать маленький портал
Я попытаюсь тут разъяснить то, как я подхожу к написанию сайтов, где могут применять подключаемые модули. Пример тому известный скрипт PHPNuke. Как бы не ругали его, подход, примененный в нем, к модульному программированию очень удобен. Но из-за корявости общего кода применять такой скрипт на серьезных сайтах, точнее скажем порталах, с большим количеством посетителей, не рекомендуется. Почему? Скрипт работает медленно, очень большая нагрузка на базу данных. Можно еще очень много чего описать, но это уже материал для другой статьи. Если кому интересно , то в интернете полно описаний этого движка. В «неудобоваримости» PHPNuke я убедился сам. Мой основной проект NVIDIA BIOS Collection в начала базировался на PHPNuke, но постоянные проблемы с хостингом заставили меня начать разработку своей система портала с нуля. Из PHPNuke я взять только суть модулей, все остальное же делал сам. И так для начала. Прежде всего, надо продумать систему каталогов, что и где будет лежать. Вот примерный вариант.
/mods/ - каталог для хранения модулей
/img/ - картинки
/inc/ - каталог вспомогательных файлов
это что нам сейчас пока надо. Применять блоки и скины мы пока не будем. В моем портале также были другие каталоги
/blocks/ - Тоже своего рода модули, но не выводящие сами информацию, а возвращающие заполненную переменную.
/js/ - каталог для Java скриптов
/theme/ - каталог выбора тем или, грубо говоря, набор скинов для сайта.
/files/ - файлы для скачивания
ну и другие каталоги.
В корневом каталоге храниться всего один файл index.php и вся работа идет через него. Теперь надо решить как будет выглядеть сам сайт. Для нашего примера подойдет наипростейший вариант дизайна , верх сайта , низ сайта, а в середине наша информация из модулей. Для этого в каталоге include создадим два файла top.php и bottom.php, что соответственно будет верхней частью дизайна и нижней частью дизайна.
top.php
<?php
echo "<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=windows-1251'>
<title>$PAGE_TITLE</title>
</head>
<body>
<table border='0' cellpadding='0' cellspacing='0' style='border-collapse: collapse' bordercolor='#111111' width='100%' id='AutoNumber1'>
<tr>
<td width='100%' colspan='2' bgcolor='#DDFFFF'>
<p align='center'>здесь выводится шапка</td>
</tr>
<tr>
<td width='17%' align='left' valign='top' bgcolor='#FFDFFF'><b>Меню сайта</b><p>
<b>- </b><a href='index.php?mod=mod1'>Модуль1</a><br>
- <a href='index.php?mod=mod2'>Модуль2</a></td>
<td width='83%' align='left' valign='top'>";
?>
Предвижу комментарии, где скажут, почему я не вывожу HTML код отдельно, а php отдельно. Я приучил себя к написанию 100% PHP кода, с одной стороны не очень и красиво может выглядеть, но мне так удобнее. Если кто-то хочет писать по-другому, то тут я не советчик. Заметьте переменную $PAGE_TITLE в top.php. В моей реализации вся информация о модулях храниться в базе данных, где помимо имени файла модуля храниться также и его название, которое потом и кладется в $PAGE_TITLE, для вывода его в головок браузера.
bottom.php
<?php
echo "</td>
</tr>
<tr>
<td width='100%' align='left' valign='top' colspan='2' bgcolor='#DDFFFF'> </td>
</tr>
</table>
</body>
</html>";
?>
Также создадим файл конфигурации config.php и положим его в каталог include.
config.php
<?php
#Модуль по умолчанию
$sys_def_mod="mod1";
?>
Вот примерная схема работы index.php:
<?php
include("inc/config.php");
if (!isset($mod) || ($mod=="") || (!file_exists ("mods/$mod.php"))) {
$mod=$sys_def_mod;
#Проверка на существование переменной $mod, и существования такого модуля
# если неверное условие то присваиваем ему значением модуля по умолчанию
}
$PAGE_TITLE="Модуль $mod";
include("inc/top.php");
include("mods/$mod.php");
include("inc/bottom.php");
?>
Теперь создадим два файла mod1.php и mod2.php и положим их в каталог mods.
mod1.php
<?php
if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
echo "Это модуль номер 1!<br>";
echo "А <a href='index.php?mod=mod2'>здесь</a> можно посмотреть на модуль номер 2";
?>
mod2.php
<?php
if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
echo "Это модуль номер 2!<br>";
echo "А <a href='index.php?mod=mod1'>здесь</a>l можно посмотреть на модуль номер 1";
?>
Поясню немного вот эту строку:
if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
В каждый модуль желательно включать такую проверку во избежании вызова файла модуля вне самого index.php. На примере моего портала до вызова модуля у меня идет подключение в базе данных, считывание некоторых глобальных переменных и без них, ни один модуль сам по себе работать не сможет. Так что лучше всего просто запретить вызов модуля напрямую. Вызов модулей в данном случае производится через строку в виде index.php?mod=имя модуля, но тут можно применить и систему ЧПУ. Тогда URL примет вид index.php/имя модуля/
Вот в принципе очень грубая схема реализации модулей. Можно добавить любой модуль, просто положив его в каталог mods/ и придерживаясь общей концепции работы, построить очень сложный сайт. В чем удобства работы? По сути вы отодвигаете от себя основную заботу по натягиванию кода на дизайн. Это делает один раз в index.php. Сам же модуль должен только работать и приносить пользу. Централизация сбора основной информации из базы или конфигурационного файла, глобальные переменные сайта, информация о пользователе и т.д. С другой стороны есть недостатки (хотя при определенном взгляде они не кажутся недостатками), скажем надо четко следить за тем какие имена переменных используются до модуля, чтобы не перезаписать, случайно, их внутри модуля. Один раз у меня такое случилось. После такого случая, я взял для себя за правило называть системные переменные в таком виде $sys_имя переменной. Другой очевидный недостаток это трудность реализации разных вариантов дизайна для разных модулей. Но! Тут есть выход тоже.
Если взять за правило, что каждый модуль обязан сам вывести шапку и низ сайта, то вам уже предоставляется свобода по выбору что и как выводить.
К примеру, наши простые модули можно модифицировать в таком варианте.
<?php
if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
$PAGE_TITLE="Это Я, модуль номер 1!!!";
include("inc/top.php");
echo "Это модуль номер 1!>br<";
echo "А <a href='index.php?mod=mod2'>здесь</a> можно посмотреть на модуль номер 2";
include("inc/bottom.php");
?>
Как делать в данном и конкретном случае решать Вам. Я же просто попытался направить тех, кто начинает писать на php, а может и тех, кто уже пишет, на определенный вариант или стиль программирования.
Маленькая баннерная сеть каждому
Представим такую ситуацию, что вы обменялись кнопками с 15 сайтами и всё пространство дизайна сайта заполнено. Что делать ??? Встаёт вопрос об изготовлении собственной маленькой баннерной сети. Но если вы не программист и не пишете скрипты сами, то нужно взять скрипт из каких-нибудь архивов скриптов. Не нужно этого делать, всё сейчас будет рассказано в этой статье.
Все баннерооменные сети используют CGI скрипты, но мы можем обойтись обычным Java скриптом. Приведём его :
<SCRIPT language="JavaScript">
// <!-- Main
function banners()
{
Это начало скрипта. Дальше идёт перечисление ссылок и соответствующих им баннеров. Мы для примера берём три ссылки.
this[1]="http://www.ваша_ссылка_01.ru"; //- Здесь вы пишете вашу ссылку.
this[2]="http://ваша_картинка_01.gif"; //- Здесь указываете путь к графичекому файлу.
this[3]="http://www.ваша_ссылка_02.ru";
this[4]="http://ваша_картинка_02.gif";
this[5]="http://www.ваша_ссылка_03.ru";
this[6]="http://ваша_картинка_03.gif";
Количество таких ссылок может быть любым. Но это ещё не весь код. Дальше идёт часть скрипта, которая как раз и отвечает за функцию одмена баннерами. Приведём его :
if ((navigator.appName == "Netscape") && (parseInt(navigator.appVersion.substring(0,1)) < 3)) {
return(' '); }
var j=(new Date()).getSeconds() % 3;
document.write('<a href=' + this[2*j+1] + ' target=blank><img src=' + this[2*j+2] + ' border=0 width=468 height=60></a>');
return(' ');
}
// -->
</SCRIPT>
<SCRIPT language="JavaScript">
// <!-- Main
banners();
// -->
</SCRIPT>
Так как мы приводим этот скрипт не только для профессионалов, но и для новичков, мы не будем разбирать все переменные скрипта. Следует разобрать только одну переменную "J". Она должна соответствовать количеству показываемых баннеров. У нас это "3". А если у вас монго страниц на сайте, следует заключить этот скрипт на отдельную страницу и включить его на все остальные методом SSI.
Ну а кто не знает что такое SSI, то может прочитать здесь.
Сделать сайт в оффлайне, от и до? Реально!
Если вы читаете эту статью, значит вам это нужно. Зачем? Не у каждого из нас есть возможность сутками просиживать в сети, не считая во сколько это выливается карману. Не все из нас могут сделать сайт сразу без ошибок и неточностей. А если проект делается "с нуля" и плюс к этому требует использования таких технологий как Perl, PHP, MySQL, SSI? Разработка и отладка в сети займет гигантское количество времени, усилий и денежных затрат. Как этого избежать? Сделать сайт на своей машине, не торопясь, вдумчиво и внимательно все проверяя, исправляя и дополняя. И только потом уже полностью готовый проект залить на сервер и провести тестирование и подгонку под конкретную конфигурацию конкретного хостинга. Заманчиво! Но это еще более заманчиво так как это реально! Итак, приступим к созданию на нашем рабочем компьютере среды, в которой можно создать полнофункциональный вебсайт.
Что понадобится
Первое что необходимо сделать, это обзавестись соответствущим программным обеспечением. Качаем из сети (версии для Windows):
Первым желательно скачать сам Apache так как пока докачивается остальное, займемся его установкой и настройкой.
Установка и настройка Apache
Установка самого Apache не должна вызвать у вас каких-то вопросов и сложностей. Сначала вы выбираете директорию, куда устанавливать сам сервер, следом название группы (оставьте как есть), а потом конфигурацию установки - выбирайте Typical. Не спешите сразу запускать сервер - ничего хорошего из этого не выйдет, сначала надо его настроить. Переходим в директорию куда вы ставили Apache, затем в директорию conf внутри этой директории и любым текстовым редактором (лучше всего блокнотом) открываем файл httpd.conf на редактирование. Находим строчку ’#Listen 12.34.56.78:80’ (здесь и далее одинарные кавычки только для четкого определения строки, в файле конфигурации их быть не должно) и заменяем ее на ’Listen 127.0.0.1:80’. Чуть ниже видим строчку ’#BindAddress *’, ее меняем на ’BindAddress 127.0.0.1’. Листаем файл еще ниже и обнаруживаем строку ’ServerAdmin you@your.address’, здесь вместо you@your.address подставляем адрес своей электронной почты. Таким образом эта строка примет например такой вид "ServerAdmin oleg@digin.ru’. Листаем еще немного ниже и видим строку вида ’#ServerName new.host.name’. Вместо нее, поскольку у нас локальная машина, вписываем ’ServerName 127.0.0.1’. А сейчас внимание. Создадим на вашем винчестере например на диске C директорию в которой будет находиться ваш сайт. Назовем ее server. Таким образом путь к вашему локальному серверу будет ’c:/server’. Запомним этот адрес, а лучше куда-нибудь запишем, он нам пригодится. После этого продолжаем конфигурировать Apache. Находим строку начинающуся со слов ’DocumentRoot’, далее в ней идет некий адрес на вашем винчестере. Вместо этого адреса подставляем адрес только-что созданной серверной директории. После этого строка может выглядеть так ’DocumentRoot "c:/server"’. Обратите внимание, что в конце адреса мы не добавляем слэш. Далее находим такой небольшой абзац: ’
<Directory/>
Options FollowSymLinks
AllowOverride None
</Directory>
’ и его полностью заменяем на приблизительно такой: ’
<Directory "c:/server">
Options Indexes FollowSymLinks MultiViews +Includes
AllowOverride None
</Directory>
’, где ’c:/server’ адрес вашей серверной директории. Затем немного ниже видим строчку начинающуюся так ’’. Далее несколько ниже обнаруживаем строку ’Options Indexes FollowSymLinks MultiViews’, ее заменяем на ’Options Indexes FollowSymLinks MultiViews +Includes’. Далее находим строку ’#AddHandler server-parsed .shtml’ и убираем перед ней значок хэша. Получаем ’AddHandler server-parsed .shtml’. На этом первоначальная конфигурация вебсервера Apache завершена, в том числе мы его настроили и для исполнения SSI директив. Сейчас, когда уже скачались Perl и PHP можно включить поддержку этих двух языков в ваш Apache, но до этого сначала поставим эти языки в систему.
Ставим Perl
Сначала добавим в систему Perl. Если Perl не нужен можно сразу перейти к следующему разделу. Установка самого Perl не вызовет у вас каких-либо затруднений. Только запомните путь к директории в которую вы его устанавливаете. Затем выключите Apache (если он у вас включен) и вновь откройте на редактирование конфигурационный файл Apache. Листаем его в самый верх и начинаем по порядку. Ищем строчку ’#!c:/program files/perl/perl’ и заменяем ее (в случае если ваш Perl вы ставили в ’c:/perl’) на ’#!c:/perl/bin/perl.exe’. Далее находим строку начинающуюся ’ScriptAlias /cgi-bin/’ и меняем в ней путь к cgi-bin директории вашего сервера. Например эта строка будет выглядеть как ’ScriptAlias /cgi-bin/ "c:/server/cgi-bin/"’. Обратите внимание что вам надо создать директорию cgi-bin в вашей серверной директории и что в конце пути здесь добавляется слэш. Еще несколькими строчками ниже видим абзац начинающийся с ’’. Еще листаем вниз и находим строчку ’#AddHandler cgi-script .cgi’. Убираем перед ней хэш и она выглядит ’AddHandler cgi-script .cgi’. Все, теперь ваш Apache настроен и для исполнения Perl-скриптов.
Установка и настройка PHP
Те, кто не пользуется PHP могут этот раздел пропустить. Так-же как те, кто не пользуется Perl могли пропустить раздел предыдущий. Итак, устанавливаем PHP. Сама установка PHP происходит элементарно. После скачивания архива распакуйте его например в директорию ’c:/php’. При этом обратите внимание что в архиве может быть запакована корневая директория, в таком случае перепишите в ’c:/php’ не ее саму а ее содержимое. После этого найдите в директории файл php4ts.dll и скопируйте его в директорию ’c:/windows/system’ (или соответственно туда, где у вас находится подобная директория). После этого необходимо вновь поправить конфигурацию Apache. Листаем файл httpd.conf в самый верх и приступаем. Найдите строчку ’# Dynamic Shared Object (DSO) Support’ и после нее добавьте две строки ’LoadModule php4_module c:/php/sapi/php4apache.dll’ (если вы ставили PHP в ’c:/php’) и ’AddModule mod_php4.c’. После этого листаем вниз и находим строчку ’#AddType application/x-httpd-php .php’, убираем здесь хэш и получаем ’AddType application/x-httpd-php .php’ а также строкой ниже добавляем ’AddType application/x-httpd-php .php3’. На этом установка PHP и настройка Apache для него закончены.
Установка MySQL
При установке базы данных MySQL серьезно отнеситесь к выбору логина и пароля для доступа к базе. Эти логин и пароль вы будете использовать для управления вашими данными. Адресом хоста вашей локальной базы будет ’localhost’. При переносе программного обеспечения, работающего с MySQL на вашей локальной машине, в интернет, не забудьте изменить данные доступа на соответствующие вашему хостингу. Apache настраивать для работы с MySQL не требуется.
Когда все поставлено и настроено
Перезагрузите машину. На всякий случай, хуже все равно уже не будет. После перезагрузки пробуем запустить все что мы тут наставили и нанастраивали. Поехали - из кнопки Start запустим Apache. Если все настроено верно то появится и не пропадет консольное окно с текстом вроде этого ’Apache/1.3.14 PHP/4.1.3-dev running...’ (в случае если мы ставили также и PHP). Если окошко выскочило и тут-же закрылось - имеет место ошибка конфигурации, но об этом позже. Итак, все запустилось, пишем какой-нибудь простенький html типа ’hello, world’, сохраняем его в ’c:/server’ как index.html и открываем в любом браузере адрес ’http://127.0.0.1’. Все:) Скажу еще что Perl-скрипты надо запускать из ’c:/server/cgi-bin’ набирая в строке запроса что-то типа ’http://127.0.0.1/cgi-bin/test.cgi’, а PHP скрипты и страницы можно запускать откуда угодно из вашей серверной директории. Да, SSI директивы также будут исполняться на вашем сервере, вот только такие файлы награждайте расширением shtml. Когда пишете скрипты, использующие в своей работе MySQL, не забывайте этот самый MySQL запускать. Выключайте Apache не закрывая консольное окно, а выбирая соответствующий пункт из программной группы Apache. И если у вас все с настройкой сервера в порядке, порекомендую вам пользоваться небольшой но потрясающе удобной утилиткой Apache Manager для запуска, перезапуска и выключения сервера. Скачать утилиту можно здесь, скопировать ее нужно в директорию к Apache, а потом просто запустить.
Если ничего не работает
Напишите в форум что и как конкретно не работает - разберемся. Только не надо писать мне на почту - на такие письма я не отвечаю.
Подводим итоги
У нас есть работающий домашний сервер, эдакий интернет в миниатюре. Запускаем Apache, MySQL и любимый текстовой редактор, открываем DOC’и, FAQ’и и прочую литературу и создаем шедевр. А если что-то непонятно - милости просим в форум, там обязательно появится ответ на ваш вопрос. На этом прощаюсь, надеюсь был вам полезен;)
Установка Apache
Прежде чем приступить к разработке сценариев РНР, необходимо установить соответствующее программное обеспечение: Web-сервер Apache и интерпретатор РНР. Операция обычно проходит быстро и без осложнений. Если же вы столкнетесь с проблемами, обратитесь к документации, прилагаемой к программам Apache и РНР.
- Запустите Web-броузер и укажите адрес http://httpd.apache.org/ или возьмите его с моего компакт-диска.
- Щелкните на ссылке Download!.
- Щелкните на ссылке Binaries.
- Щелкните на ссылке Win32.
- Вы увидите список с несколькими версиями Web-сервера Apache. Выберите нужную вам и "скачайте" ее. На момент подготовки книги последней версией была 1.3.14. Кроме нее, можно было использовать версию 1.3.12.
- В броузере должно открыться диалоговое окно с запросом о том, хотите ли вы сохранить данный файл. Сохраните файл на жестком диске.
- Перейдите в папку, в которой вы сохранили файл дистрибутива Apache, и дважды щелкните на нем. Произойдет запуск программы инсталляции сервера Apache.
- Установите сервер Apache на своем компьютере. Для этого надо только следовать инструкциям мастера установки, который выполнит все необходимые действия, запрашивая при необходимости дополнительную информацию (например, о том, в какую папку установить программное обеспечение).
- Запустите сервер Apache. Сервер версии 1.3.14 может быть введен в действие либо как обычная программа (в этом случае откроется окно DOS-сессии), либо как служба (service) Windows NT. Чтобы сервер работал как служба Windows NT, следует открыть панель управления, найти среди служб Apache и запустить ее. Кроме того, вы можете задать режим включения данной службы - "автоматический", "вручную" или "недоступен".
- Откройте броузер и укажите адрес http://localhost/.
- В броузере должна отобразиться страница.
- Если страница отобразилась, то установка Apache произведена успешно!
|