|
Бесплатная раскрутка сайтов |
Все файлы на этом сайте
проверены антивирусом |
|
Основы PHP Вы вышли за рамки статических www-страниц? Вам требуется обрабатывать html-формы? Вы хотите сделать интефейс с базой данных через веб? Электронный магазин? Счетчик с подробной статистикой или опрос посетителей вашего сайта (см. «Мир Internet», #11'99)? Есть множество программ, работающих через интерфейс CGI, как правило, написанных на языке Perl, но сегодня существуют и другие возможности. Почему PHP? Perl - очень хороший, мощный язык, но слишком высоки системные издержки во время вызова программы на каждый запрос страницы, особенно в Windows. Существуют ли альтернативы? В последние годы быстро набирает популярность язык программирования веб-приложений PHP (Personal Home Page, www.php.net). В 1994 году Расмус Лердорф (Rasmus Lerdorf) начал разработку встроенного в HTML языка программирования, исполняющегося на стороне сервера. Со временем к проекту присоединились и другие разработчики, и сейчас PHP - это бурно развивающееся средство программирования, работающее на очень многих серверах в Интернете. Как средство разработки www-приложений PHP сейчас лидирует - вместе с ASP, FrontPage и mod_perl. Достаточно полно описать язык программирования и сопутствующие инструментальные библиотеки в одной статье невозможно, однако можно постараться: не описывая синтаксис или библиотечные функции, полезно остановиться на особенностях создания скриптов на PHP. А с подробной документацией по PHP можно ознакомиться на сайте www.php.net/manual. PHP можно установить в двух вариантах: как отдельный интерпретатор, работающий через интерфейс CGI, или как модуль веб-сервера, встроенный в сам сервер. В последнем случае становятся актуальными все преимущества PHP. Из аналогичных встроенных в сервер программных средств хорошо известны SSI, mod_perl, ASP. Но SSI обладает довольно ограниченными возможностями, а mod_perl, на мой взгляд, слишком много умеет. Ближайшим аналогом PHP является ASP, но технология ASP не прижилась в мире Unix/Apache, где простой, удобный и быстрый язык PHP постепенно завоевывает первые ряды. Сейчас распространена версия 3 интерпретатора PHP, версия 4 пока еще находится в стадии бета-тестирования. Принципиальных отличий четвертой версии от третьей нет, есть только несколько изменений синтаксиса (описанных на сайте www.php.net/version4/incompatibilities.php), которые большинство пользователей не заметит: подавляющее большинство скриптов будут работать в обеих версиях языка. Как и все процедурные языки, PHP можно разделить на собственно язык и библиотеку функций. Существует большое количество инструментальных средств для PHP, интерфейсы ко всем популярным СУБД, почтовым протоколам, к разделяемой памяти, графическим файлам, архивам и множество других инструментов. Основы языка PHP Скрипт на PHP представляет собой файл, как правило, с суффиксом .phtml, .php3 или .php, который внутри выглядит как обычная страница на HTML. Отличие проявляется только в виде хитрого тега <?php ?>, делающего из HTML настоящий язык программирования. Часто применяют сокращенную форму <? ?>или, для совместимости с визуальными средствами формирования страниц, <% %> . Будем разумно придерживаться традиции и пользоваться тегом <? ?>. Внутри этого тега располагается код на языке PHP. Вот тривиальный пример страницы: <? include('header.html' ?>
|
<? for ($i=0; !feof($fp); $i++) : // пока не конец файла // читаем строку, отрезаем пробелы в конце и разбиваем ее на поля. list($a,$b,$c)=split("\t",chop(fgets($fp,1000))); ?> | |||
»> |
|
|
|
<? endfor ?> |
<? fclose($fp); endif ?>
PHP имеет достаточное количество встроенных функций для работы с файлами, но частенько хочется этот набор несколько расширить. Например как сделать www-чат? В теории все просто, все посетители пишут в один файл и читают последние N строк этого файла. Конечно, хотелось бы читать этот файл не последовательно с начала. Я предлагаю вашему вниманию функцию tail(), которая работает очень быстро не зависимо от размеров читаемого файла.
<?
if (!$tail_inc) : // Чтобы не включать файл дважды
$tail_inc=1;
function tail($file,$num) {
// читаем $num последних строк файла $file
global $tail_start_buf; // предполагаемая длина строки
if ($tail_start_buf==0) $tail_start_buf=80;
$appxlen=$tail_start_buf;// примерная длина строки для расчета
$flen=filesize($file); // длина файла
$out=array(); // то, что вернется
$fp=@fopen($file,'r');
if ($fp) {
do {
// вычисляем, откуда читать файл
if ($num*$appxlen>$flen) $pos=0;
else $pos=$flen-($num*$appxlen);
$out=_readfile($fp,$pos,$num); // читаем строчки до конца файла
// на следующий цикл длиной строки считаем удвоенную среднюю
прочитанную
$appxlen=($flen-$pos+1)*$num*2/count($out); // *!*
} while (count($out)!=$num && $pos!=0);
fclose($fp);
}
return $out;
}
// вспомогательная функция
// читает файл $fp с позиции $pos и максимум $num строк
function _readfile($fp,$pos,$num) {
fseek($fp,$pos); // позиционируем файл
$tmp=array(); // временный массив
while (!feof($fp)) { // читаем файл до конца
$line=chop(fgetsl($fp)); // *!!*
$tmp[]=$line;
}
$j=count($tmp)-$num; // кол-во лишних строк
if ($pos!=0 && $j==0) { // если ровно сколько надо строк,
$j++; // пропустить первую неполную
}
if ($j<0) { // если не хватает строк,
$j=0; // выводить все
$xnum=$num-1;
} else $xnum=$num;
// переписать в выводной массив нужные строки.
for ($i=0; $i<$xnum && $j
Я не буду утверждать, что это лучший на свете алгоритм, и принимаю все предложения по его улучшению. Есть два замечания сразу.
*!* Здесь вычисляется средняя длина строки для следующего цикла. У меня это отлично работало и при $appxlen*=2, но так, наверно, быстрее будет. *!!* Здесь я применил функцию fgetsl(), но это особый разговор.
Функция чтения строки из файла имеет ограничение на длину считываемой строки. А думать о длинах строк при написании гениальных скриптов не хочется. Как быть? Я предлагаю небольшую функцию, аналогичную fgets(), но без неприятного ограничения:
<?
function fgetsl($fp) {
while (!feof($fp) && strchr($out,"\n")) $out.=fgets($fp,1000);
return $out;
}
?>
Авторизация посетителя сайта на PHP
Если вы решили продавать содержимое сайта или просто ограничить доступ к некоторой его части по паролю, то имеется возможность контролировать этот процесс с помощью PHP. Вопрос авторизации решается в PHP элегантно и просто. Я один раз оформил нужный фрагмент кода как включаемый файл и использую его уже больше года. Здесь я приведу код в несколько сокращенной общей форме:
<?
if (!$auth_inc) :
$auth_inc=1;
// Параметры:
// $realm область действия авторизации.
// $sorry имя файла, что будет показан при отказе от авторизации
// $tmp* необязательные параметры для функции проверки пароля
function authCheck($realm,$sorry=",$tmp1=",$tmp2=") {
global $PHP_AUTH_USER;
global $PHP_AUTH_PW;
if(!isset($PHP_AUTH_USER)) {
Header("WWW-Authenticate: Basic realm=\"$realm\"");
Header("HTTP/1.0 401 Unauthorized");
if ($sorry == ") echo "Вам отказано в доступе!";
else {
include($sorry);
}
exit;
} else {
if (@authFunction($PHP_AUTH_USER,$PHP_AUTH_PW,$tmp1,$tmp2)) {
$ok=1;
} else {
Header("WWW-Authenticate: Basic realm=\"$realm\"");
Header("HTTP/1.0 401 Unauthorized");
if ($sorry == ") echo "Вам отказано в доступе!";
else {
include($sorry);
}
exit;
}
}
}
endif;
?>
Функцию authFunction() пишет сам пользователь, она получает аргументами, соответственно, логин и пароль, введенные посетителем, и два необязательных параметра по наследству от authCheck(). Автор скрипта должен просто включить файл auth.inc в свою программу, написать функцию authFunction(), которая, например, будет проверять пользователя по базе данных, и вызвать функцию authCheck() перед каким-либо выводом текста страницы, как было замечено про функцию setcookie(). Написание разных authFunction() позволяет контролировать доступ посетителей из множества различных источников, таких как файлы паролей, СУБД, хэш-файлы, запросы к сетевым сервисам авторизации, и из любых на ваше усмотрение.
Такой тип авторизации самый, так сказать, железный. При посещении закрытой страницы посетителю выдается диалоговое всплывающее окно с полями имени и пароля. В дальнейшем броузер запоминает $realm и при последующем запросе пароля будет автоматически отправлять серверу пару имя/пароль. Однако это не единственный способ авторизации. Пример писать не буду, а просто потеоретизирую немного. Описанная выше система ведения пользователя вполне подойдет с небольшими модификациями. Для регистрации создадим форму с полями login и password. Обработчик формы генерирует случайный уникальный ключ и записывает с ним дату/время регистрации в хэш-файл. Вместо даты и времени годится значение функции time(), возвращающей количество секунд с 01.01.1970. Броузеру клиента выдается cookie, например, xfile со значением только что сгенерированного ключа. Каждая страница, требующая авторизации, должна проверить наличие ключа $xfile в хэш-файле и, если он есть, записать туда время обращения, не затрагивая времени регистрации.
Для отказа от авторизации достаточно удалить ключ из базы. Внешняя программа может раз в полчаса, допустим, удалять ключи, выданные 3 часа назад, и ключи, к которым не было обращения в течение 1 часа. Стойкость такой системы определяется трудностью подбора ключа-cookie за ограниченное время, так как ключи живут относительно недолго и они достаточно длинные. Ключ можно передавать не только через cookie, но и через URL как параметр скрипта.
Конечно, гениальный автор сайта сам должен решить, какой алгоритм авторизации он себе выберет, так как у обоих вариантов есть свои плюсы и минусы. Возможно, есть еще какие-либо варианты. Пишите, обсудим.
В общем-то ведение пользователя и авторизация - это ключ к созданию электронного магазина. Может быть, об этом я тоже когда-нибудь напишу.
Работа с базами данных на PHP
А какой же электронный магазин без базы данных? В принципе, можно и без нее, но насколько СУБД облегчает разработку подобных проектов. PHP поддерживает множество СУБД от xBase до дорогих коммерческих SQL-серверов. Особого внимания заслуживают такие базы, как MySQL (www.tcx.se) и PostgreSQL (www.postgresql.org) - по причине их популярности, хороших характеристик и бесплатности. Легкодоступность СУБД и интерфейса к ней побуждает юные умы применять базу данных направо и налево, не особенно задумываясь о необходимости применения и об алгоритмах работы с базой.
Самая распространенная ошибка авторов скриптов - это отношение к СУБД как к чему-то сверхоперативному. А это вовсе не так. Вот пример, как не надо писать скрипты:
<?
1 pg_pconnect("host=localhost dbname=test");
2 $s1=pg_exec("select a from b");
3 for ($i=0; $i
4 $a=pg_result($s1,$i,0);
5 $s2=pg_exec("select c,x,y,z from d where e=$a");
6 for ($j=0; $j
7 $c=pg_result($s2,$j,0);
8 $x=pg_result($s2,$j,1);
9 $y=pg_result($s2,$j,2);
10 $z=pg_result($s2,$j,3);
11 echo "$c $x $y $z
\n";
}
}
?>
1 - надо трижды подумать, прежде чем иcпользовать постоянное соединение с базой. Здесь выбран хост localhost, но работа с локальным сервером через unix socket может быть быстрее.
2 - надо проверить, выполнился ли запрос без ошибок.
3 - нехорошо вызывать функцию в цикле, лучше завести дополнительную переменную $num=pg_numrows($s1).
5 - самая грубая ошибка: запрос в цикле по другому запросу, от такого программирования не спасут ни множество процессоров, ни обилие памяти, ни быстрая дисковая система. Почему бы не решить проблему в один запрос?
$s1=pg_exec("select a,c,x,y,z from b,d where e=a order by a");
В цикле можно запомнить предыдущее значение $a и прерывать цикл при смене этого значения. В любом случае, чем меньше запросов будет к базе, тем лучше - имейте это в виду.
7-10 - можно не вытаскивать поля по одному, а применить функцию pg_fetch_array() или pg_fetch_object(), которые возвращают хэш и объект соответственно с именами полей, соответствующими именам полей результата запроса.
PHP позволяет поддерживать постоянные соединения с СУБД. То есть при завершении скрипта соединение с сервером базы данных разорвано не будет, а будет возобновлено при повторном запросе. Такой метод работы очень экономит время соединения, но съедает системные ресурсы (память, дескрипторы и т. д.). Если у вас один пользователь базы, одна база и один сайт, который непрерывно обращается к базе, то вам стоит попробовать поэкспериментировать. В конфигурации PHP можно глобально отменить постоянные соединения, чем и пользуются провайдеры, чтобы защитить свои хосты от жадных пользователей.
Раз уж мы начали говорить об электронной торговле, то можно развеять еще одно заблуждение, - что MySQL для нее годится. Это не совсем так. Он годится для макета, но не для серьезного сайта. В MySQL нет транзакций. Для сложной базы, для денежных расчетов, для оформления заказов и многих других важных операций транзакции необходимы. Так что используйте PostgreSQL, который все это умеет.
Допустим, магазин вы организовали, заработали кучу денег, давайте теперь продолжим ознакомление с программированием на PHP. Вкратце коснусь других возможностей.
Работа с электронной почтой на PHP
Чего вожделеет каждый веб-мастер, создав на странице форму? Да, отправить ее содержимое себе по почте. А сделать это на PHP очень просто - есть функция mail($to,$subj,$body, $header). Но есть и тонкость: почта будет уходить от имени www-сервера (как пользователя). Не забывайте, пожалуйста, про четвертый аргумент $header, в котором вы можете указывать любой параметр заголовка письма (см. RFC-822):
mail('user@isp.ru','test message','Выполучили
письмо',
"From: bill@gates.ru\nContent-type: text/plain;
charset=windows-1251");
Указывайте хотя бы From: и Content-type: - это предохранит вас от раздраженных получателей писем или, если получаете вы, от получения писем в непонятной кодировке неизвестно от кого.
Одно время у провайдеров были популярны системы чтения/отправки электронной почты с www-сайта. На PHP вы можете сделать то же самое. Достаточно лишь почитать описание протоколов POP и IMAP и открыть сетевое соединение с почтовым сервером. Функция fsockopen(хост, порт) открывает сетевое соединение, а пользоваться им можно при помощи обычных файловых функций. Только не открывайте соединение к своему www-серверу и не запрашивайте свой же скрипт - веб-мастеру это может сильно не понравиться. В целом работа с сетью в PHP оставляет желать лучшего - надеюсь, многие изъяны будут исправлены в четвертой версии. В первую очередь не хватает функции select() или аналога соответствующему вызову POSIX. Сетевое соединение - это не совсем файл, оно может прерваться, другая программа может не закрыть соединение и завершиться/зависнуть и т. п. Функция select() позволяет сделать работу с сетью более надежной. Подождем.
О корректной работе PHP
Не следует забывать еще про одно сетевое соединение - соединение клиента с веб-сервером, во время которого выполняется скрипт. Представьте себе ситуацию, когда ваш скрипт обрабатывает сложный запрос, что-то читает из базы, пишет в файл, изменяет данные в базе и т. д., а во время этого процесса клиент нажал кнопку «Стоп» и разорвал соединение. Процесс работы вашей программы будет прерван в самый неожиданный момент, и обработка не будет завершена. Но частично-то работа проделана. Необходимо как-то откатить назад внесенные изменения. Для этого в PHP встроен механизм контроля за соединением. Вы можете подготовить функцию аварийной остановки с помощью register_shutdown_function(функция). Заданная функция вызывается интерпретатором PHP при завершении работы скрипта. Сетевое соединение в PHP находится в следующих состояниях:
0 - NORMAL;
1 - ABORTED;
2 - TIMEOUT.
Когда PHP работает нормально, статус соединения будет NORMAL. Когда клиент прерывает соединение, устанавливается флаг ABORT. Если для выполнения скрипта не хватило времени, то будет установлен флаг TIMEOUT.
Вы можете указать интерпретатору, будет или нет ваш скрипт прерван при разрыве соединения. Этот вариант можно выбрать функцией ignore_user_abort(). Другой вариант - это создание функции аварийного завершения, как было описано выше. При ее выполнении вы можете задать проверку причины завершения при помощи функций connection_aborted(), connection_timeout() и connection_status(). Если вы использовали ignore_user_abort(), то функция аварийного завершения может обнаружить два статуса, ABORT, если пользователь прервал соединение, и TIMEOUT если при этом скрипт выполнялся слишком долго.
Как известно, для пользователя самый страшный враг - это сам пользователь. А если таких много на одном сервере? И обязательно найдется некто, который назовет себя «куул хацкером» и начнет либо искать спрятанную информацию, либо просто пакостить. В PHP предприняты попытки ограничить возможности пользовательского скрипта, чтобы предотвратить возможность утечки информации и порчи чужих данных. Провайдеры обычно разрешают пользователям выполнять скрипты в «безопасном режиме». Сильно это ограничение не сковывает, но помнить об этом надо.
* * *
Что ж, осталось найти хостинг с поддержкой PHP, почитать документацию и создать отличный динамичный сетевой ресурс, от которого все ахнут. Я надеюсь, что эта статья поможет вам разобраться в дебрях программирования для www-серверов. PHP хороший язык, попробуйте - вам понравится!
Комментарии: Пишите мне | Copyright © |