По ту сторону Веб-страницы

Сайт выполняет черную работу

С одной стороны, чаще всего при создании сложных сайтов прихо­дится выполнять десятки и сотни рутинных операций. Примеров масса. В каждый из файлов должен быть вставлен навигационный блок; при этом на каждой данной странице ссылка на эту страницу должна быть заменена обычным текстом. При подготовке статис­тических таблиц приходится каждый раз повторять одинаковые фрагменты данных. Если верстка всех страниц сайта основана на одном шаблоне, то дело, конечно, упрощается.

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

Включать этот файл в нужном месте. Так поступают с фрагментами, со­держащими навигационное меню и другие повторяющиеся фрагменты: добавление в меню одного раздела в связи с этим сводится к добавлению одной строчки в один файл, а не к редактированию каждой страницы.

Приведем пример. Допустим, на сайте есть несколько разделов, каждый из которых «обслуживает» одна ссылка в меню. Сайт состоит из непостоянного количества страниц: периодически разделы то добавля­ются, то удаляются. Меню представляет собой строчку, в которой ссыл­ки разделяются обратным слэшем; после последней ссылки, понятное дело, слэша нет. Создаем файл сценария на языке PHP (назовем его navi. php). Один из вариантов сценария, создающего меню, может вы­глядеть так:

<p><?

$navig = array();

$navig["news. php"] = "Новости"; $navig["service. php"] = "Сервис"; $navig["decision. php"] = "Решения"; $navig["partner. php"] = "Партнеры"; $navig["sotr. php"] = "Сотрудничество"; $navig["integration. php"] = "Интеграция"; $navig["download. php"] = "Загрузка"; $navig["faq. php"] = "Вопрос — ответ";

$navbar = ''; foreach($navig as $k=>$v)

{

If($k == $SCRIPT_NAME)

{

$navbar.='<span style="color:#FFA8 0 0"><b>'.$v.' </b></span> ';

}

Else

{

$navbar.='<a href="/'.$k.'">'.$v.'</a> ';

}

}

$navbar = substr($navbar,0,strlen($navbar)-3); echo $navbar;

?></p>

Код, может быть, и выглядит несколько громоздким, но он за­писан всего один раз, а не 8 (по количеству разделов). Что он делает? Сначала создает массив ($navig), в каждом из элементов которого

Присутствует пара «ключ — значение». Ключ отвечает за название фай­ла страницы, а значение — за заголовок. После этого создается строка, в которую циклом, считывающим элементы массива один за другим, добавляются уже отформатированные ссылки с разделителями. В конце ненужный разделитель () отрезается, и строка (скрытая под именем переменной $navbar) выводится с помощью оператора echo в бра­узер. Более того, сценарий проверяет, не совпадает ли «ключ» (назва­ние файла страницы) в будущем меню с названием файла загруженной страницы, и если совпадает, то вместо ссылки формируется оранжевый полужирный заголовок страницы (для сохранения целостности меню названия загруженного раздела не удаляется из строки).

Теперь достаточно в каждом файле написать такой код:

<?

Require "navi. php";

?>

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

Для работы серверных сценариев должны выполняться несколь­ко условий.

Во-первых, на сервере, где будут располагаться страницы со сце­нариями, должна присутствовать поддержка нужного языка. При по­купке выделенного сервера или при его аренде (виртуальный хостинг) всегда нужно интересоваться, какие языки поддерживаются на сервере. Например, сервер, который я арендую, поддерживает PHP 4 и 5, SSI, Perl и некоторые другие языки и технологии.

Во-вторых, следует знать, какие расширения файлов вашего сай­та допустимы для выполнения в них серверных сценариев. Например, для работы сценариев на языке PHP файлы должны иметь расширение. php. Однако, если на сервере (обычно если это сервер с установленной операционной системой Linux или FreeBSD) разрешено размещение и редактирование файла. htaccess, то возможности богаче: достаточно добавить строчку

I AddHandler application/x-httpd-php. php. html. htm

В этот файл, чтобы интерпретатор PHP корректно обрабатывал также фай­лы с расширениями. html и. htm. Разумеется, вы можете сохранять файлы с любыми экзотическими расширениями — главное, чтобы в конфигу­рационном файле эти расширения ассоциировались с интерпретатором PHP (тогда они автоматически будут обрабатывать и обычный HTML).

4

Программирование

В-третьих, синтаксис сценариев должен быть корректным. Если в файлах допущена ошибка, а контроль ошибок отключен, то на восста­новление работоспособности может уйти очень много времени.

«Роботов», помогающих веб-разработчику в повседневной работе, не так уж мало. Назовем самые известные из них. SSI — не язык, а ско­рее достаточно простая и ограниченная в возможностях технология, используемая в контексте других языков. О ней будет подробно расска­зано чуть ниже. ASP (Active Server Pages, «активные серверные страни­цы») — также не язык, а технология серверного использования языков активных сценариев. То есть код, например, на языке VBScript выпол­няется на сервере, и этот код, в отличие от клиентского выполнения, не выводится в браузер. Напротив, результат этого кода отправляется в браузер посетителя. Файлы, использующие эту технологию, имеют рас­ширение. asp, а код, находящийся внутри кода на HTML, обособляется от него маркерами <%...%>. То есть то, что следует после <% и до пер­вого %>, обрабатывается как ASP-код. Perl — очень мощный язык, при­годный не только для разработки веб-страниц. Файлы, обрабатываю­щиеся этим языком, имеют расширения. pl или. cgi и располагаются в отдельных директориях, не смешиваясь с кодом на языках разметки и активных сценариев. К слову, серверное включение файлов и в сце­нариях на Perl, и на страницах с использованием ASP осуществляется с помощью технологии SSI. В отличие от них, PHP имеет собственные технологии включения; для динамического создания веб-страниц он использует только «внутренние ресурсы». Файлы с расширением. php, .php3 и. phtml (последние два очень редко) могут включать, а могут и не включать PHP-код. В любом месте страницы разместить код на PHP можно, ограничив его маркерами <?php... ?> или просто <? ... ?>, аналогичными маркерам <%...%> на ASP. Маркеры, в точности сов­падающие с маркерами ASP, использует и язык JSP (Java Server Pages), достаточно гибкий с точки зрения отделения формы от содержания и обращений к базам данных, но не так часто использующийся по сравне­нию с PHP и Perl. Файлы имеют расширение. jsp. Язык Python (файлы. py) используется реже; он имеет достаточно строгий синтаксис. Сайты на языке ColdFusion (файлы. cfm) в Рунете почти не встречаются, хотя возможности этого языка также достаточно велики. Язык Parser по сте­пени погруженности его кода в код HTML является рекордсменом: ни­каких ограничительных маркеров нет. Сервер настраивается так, чтобы при включении в HTML-файлах директив на Parser’e они обрабатыва­лись на сервере, а уже итоговый HTML-файл посылался в браузер. На­конец, есть язык Ruby, ныне за рубежом чаще всего использующийся в связке «Ruby on Rails» — о нем в этой книге рассказано отдельно, хоть и кратко.

Три технологии из перечисленных наиболее распространены — это Perl, PHP и SSI. Первый — наиболее мощный, но для начинающе-

278

Сайт выполняет черную работу

4.3

Го разработчика более сложный, чем PHP: последний же, хотя и более вольно обращается с типами данных, обеспечивает тем самым гибкость работы, а тот факт, что фрагменты PHP-сценариев могут находиться в любом месте HTML-разметки (например, внутри тэгов или стилевой разметки), позволяет сильно сократить сам объем кода. SSI же очень прост и ограничен, годится только для нескольких целей, о которых сейчас и будет рассказано.

SSI (сокращение от Server Side Include, или «Включение на сторо­не сервера») является простейшей серверной технологией: она не под­держивает циклов, массивов и функций, и ее главное достоинство — возможность серверного включения файлов и использование условных операторов. Файлы, с возможностью обработки SSI, обычно имеют расширение. shtml, хотя сервер можно настроить так, что SSI-директи­вы смогут обрабатываться и в файлах с другими расширениями (.htm, .html) и вовсе без расширений.

Формат SSI-директив всегда одинаков:

<!--#SSI директива="параметры" -->

Внешне такие директивы похожи на HTML-комментарии. Если открыть такой документ вне сервера, то директив просто не будет видно, потому что браузер расценит их как комментарии. После знака диеза (решетки) следует название директивы (их всего несколько), которая может принимать параметры.

Например, директива echo var используется для вывода стандар­тных переменных (REMOTE ADDR — IP-адрес посетителя сайта, HTTP USER AGENT — комплексаная информация о браузере, SERVER NAME — имя сервера, HTTP REFERER — адрес страницы, с которой посетитель пришел на данную страницу). Такие переменные бывают полезны при формировании условий: например, информацию о браузере можно ис­пользовать для генерирования разных фрагментов кода для разных бра­узеров, а имя сервера — для автоматической генерации адресов.

Например, такой фрагмент кода:

<Ь>Идентификатор вашего браузера:

<!—#echo var="HTTP USER AGENT"—></b>

В случае с Opera 9 на экран будет выведена следующая запись: Идентификатор вашего браузера: Opera/9.10 (Windows NT 5.1; U; ru)

Используя данные таких записей и условные операторы, можно генерировать разные проблемные участки кода для различных брау­зеров.

SSI

Переменные, естественно, можно и назначать. Для этого сущес­твует директива set var. Ее формат: set var="ИМЯ_ПЕРЕМЕННОЙ" value="ЗНАЧЕНИЕ":

<!—#set var="SERVER_NAME" value="Www. ya. ru" —> Значение переменной SERVER NAME:

<!—#echo var="SERVER_NAME" —>

Вывод будет таким:

Значение переменной SERVER_NAME: Www. ya. ru

Несомненно, одной из самых важных директив являются дирек­тивы включения файла: include file и include virtual. Первый вид используется, если включаемый файл находится в том же катало­ге, что и запрашивающий его файл, второй вид — если нужно указы­вать путь к файлу. Таким образом, можно подготовить два файла: один (header. shtml) будет отвечать за весь код до заголовка страницы, а вто­рой (footer. shtml) — за все, что следует после изменяемого содержания. В этом случае стандартная страница может выглядеть так:

<!--#include file="header. shtml" -->

^1>Заголовок страницы<^1>

<р>Текст на странице</р>

<!--#include file="footer. shtml" -->

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

Для тех разработчиков, которые привыкли сообщать посетителю информацию о странице, существует две директивы: fsize file выво­дит размер указанного файла, а flastmod file выводит время послед­ней модификации указанного файла. Вот примеры кода:

Размер этой страницы:

<!—#fsize file="ssi. shtml"—> <br>

Время последней модификации этой страницы: <!--#flastmod file="ssi. shtml"-->

Директивы exec cmd и exec cgi запускает внешнюю про­грамму и cgi-скрипт соответственно и выводят в содержимое страни­цы вывод.

Сайт выполняет черную работу

4.3

Три директивы — config errmsg, config sizefmt и config timefmt позволяют модифицировать вывод сообщения об ошибке (в случае ненахождения включаемого файла), формата размера файла и даты модификации документа. Например, чтобы заменить стандарт­ное сообщение об ошибке [an error occurred while processing this directive] на свой текст, можно написать следующее:

<!--#config errmsg="Ошибка, будем разбираться."-->

Вместо слов «Ошибка, будем разбираться.» подставьте нужный вам текст.

В качестве параметров директивы config sizefmt обычно употребляется abbrev (сокращенная форма вывода, что-то вроде 12k) и bytes (значение выводится в байтах: 12,500):

<!--#config sizefmt="bytes"-->

Директива config timefmt меняет формат вывода даты и време­ни модификации страницы. Например, чтобы на странице появилась надпись: «Дата модификации этой страницы: 28.12.2003», следует сде­лать следующую запись:

<!—#config timefmt="%d.%m.%Y"—>

<!--#flastmod file="название файла"-->

Формат простой: сначала конфигурируем вывод, затем выводим данные. Параметры, используемые в значении этой директиве конфи­гурации, таковы:

%a Английская аббревиатура названия дня недели — Sun %A Полное название дня недели — Sunday %b Аббревиатура названия месяца — Jan %B Полное название месяца — January %d День месяца — 01

%D Дата в формате "%m/%d/%y" — 01/31/90

%e День месяца — 1

%H Часы в 24-часовом формате — 13

%I Часы в 12-часовом формате — 01

%j День года — например, 235

%m Номер месяца — 01

%M Минуты — 03

%p AM или PM

%r Время в формате "%I:%M:%S %p" — 11:35:46 PM %S Секунды — 34

%s Время в секундах с 01.01.1970 — 957228726 %Т Время в формате "%H:%M:%S" — 14:05:34 %U Неделя года — например, 49 %w Номер дня недели — 5 %у Год в формате ГГ — 95 %Y Год в формате ГГГГ — 1995 %Z Временная зона — MSK

Директива printenv выводит в браузер все переменные окруже­ния и не принимает никаких параметров.

<!--#printenv -->

На выводе в том числе окажутся: корневая директория сайта, ко­дировка, типы документов, язык браузера, имя сервера, объект HTTP_ REFERER (страница, с которой перешел посетитель), сведения о брау­зере, указания на IP и порт, имя сценария и путь к нему, метод запроса данных, дата изменения и другие сведения.

Выше упоминалась возможность выбора в зависимости от усло­вий. SSI поддерживает условные операторы if («если»), elif («если же», «в другом случае, если»), else («в остальных случаях») и endif (ко­нец блока условных операторов), из которых обязательными являются первая и последняя. Приведем пример, где в зависимости от значения переменной DOCUMENT_NAME на страницу выводится разный текст:

<!—#if expr="$DOCUMENT_NAME=index. shtml" —>

Вы находитесь на главной странице <—#elif expr="$DOCUMENT_NAME=vip. shtml" —>

Вы находитесь на очень важной странице <--#else -- >

Вы находитесь на какой-то другой странице <--#endif -->

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

<!--#config timefmt="%S" --><!--#set var="dt" value="$DATE_LOCAL" —>

<!--#if expr="$dt < 20" --><!--#include file="r1. shtml"--><!--#elif expr="$dt < 40" --><!--#include file="r5.shtml"--><!--#else --><!--#include file="r6. shtml"--><!--#endif -->

Сайт выполняет черную работу

4.3

Сначала конфигурируется формат вывод даты. Затем инициали­зируется переменная, к которой приравнивается уже сконфигуриро­ванное время (секунды). Эту переменную мы сравниваем с текущим ко­личеством секунд, и в зависимости от полученного числа включаются разные файлы (которые надо заранее подготовить). В качестве операто­ров сравнения используются =, != (не равно), <, <= (меньше или рав­но), > и >= (больше или равно). Если вторая строка заключена в слэши, условие истинно, если в первой строке встречается хоть одно вхождение второй строки. Можно объединять несколько операторов сравнения с помощью операторов && («и») и || («или»). Для группирования усло­вий используются скобки. Пример:

Браузер:

<!—#if expr="$HTTP USER AGENT=/Nav/ || $HTTP USER AGENT=/Mozilla/" —>

Netscape Navigator

<!—#elif expr="$HTTP USER AGENT=/MSIE/" —>

Internet Explorer

<!--#else -->

Альтернативный (<!--#echo var="HTTP USER AGENT"

-->)

<!--#endif -->

Вывод получится таким:

Браузер: альтернативный (Opera/9.10 (Windows NT 5.1; U; ru))

Язык PHP является полноценным и мощным средством веб-про­граммирования. В нем есть все (и иногда даже больше) инструменты, привычные для языков сценариев: операторы, переменные, константы, массивы, циклы, условные операторы и функции, огромное количество встроенных функций, средства для работы со строками и целыми фай­лами (в том числе с файлами как со строками), датами и временем, регу­лярными выражениями, средства обработки изображений и обращения к разным типам баз данных, возможность работы с XML (с пятой вер­сии), работа с Cookies и возможность загрузки файлов, хорошая интегри­рованность с сервером Apache и базой данных MySQL, лояльность к ти­пам данных (числовые, строковые, булевы) и объявлению переменных, средства подавления ошибок и возможность настройки языка под себя. И еще один немаловажный момент: PHP поддерживается на большинс­тве российских и зарубежных профессиональных хостинг-площадок.

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

PHP

Ности возможностей. Четвертая на данный момент наиболее распро­странена, и в большинстве случаев она способна удовлетворить боль­шинство запросов разработчиков. Пятая версия разрабатывалась с учетом концепции объектно-ориентированного программирования, в ней стабильно поддерживается работа с XML (в четвертой версии при­ходится использовать дополнительные модули или писать сценарии для анализа XML-документов самому), улучшена работа со временем и датами, внедрено большое количество новых полезных функций. Если на сервере стоит интерпретатор PHP 5, то в подавляющем большинстве случаев сценарии на PHP останутся работоспособны. Напротив, функ­ции, введенные в PHP 5 , не будут работать на серверах с установленным PHP 4. Рассмотрим основные возможности этого популярного языка.

Код PHP обычно погружен в код на HTML или CSS, поэто­му можно динамически генерировать разметку средствами PHP. Код на PHP отделяется от остального кода маркером <? в начале кода и?> в конце.

Все переменные, вне зависимости от типа, начинаются со знака доллара. Любую переменную, как и значения, можно вызвать операто­ром echo:

<?

$text = "12345";

Echo $text;

?>

Все первые примеры PHP в любом учебнике абсолютно бес­смысленны, и я не стану нарушать эту традицию. В первой строчке инициализируется переменная, оригинально названная $text. Ей при помощи оператора присваивания (= не означает «равно»: оно обозна­чает, что присваивается значение; «равно» в PHP записывается как ==, то есть двойным «равно»; есть еще оператор из тройного «равно», или ===, который обозначает «равно», но более строг к типам сравнивае­мых данных) присваивается значение 12345 , причем, поскольку это не оператор, не константа, не функция и не иное зарезервированное сло­во из PHP, то оно записывается в кавычках. Если внутри этих кавычек нужно употребить кавычки, то внутренние кавычки предваряются слэ­шами, но можно внешние кавычки сделать одинарными. Иначе гово­ря, если нам нужно присвоить переменной $text значение «I like "Pepsi" very much», то мы вынуждены будем записать

$text = "I like "Pepsi" very much";

Или

$text = 'I like "Pepsi" very much';

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

Что делает оператор echo (и его аналог print)? Он выводит со­держимое переменной, следующей за ним, на экран, в браузер. То есть если переменной $text присвоено значение «12345», то echo выведет текст «12 34 5». И так далее. Есть оператор конкатенации, точка, соеди­няющая строчки. Она работает так:

<?

$abc = "1234";

$def = "5678"; echo $abc.$def;

?>

В результате чего на экране появится загадочная, но вполне ожи­даемая надпись: 12345678. Обратите внимание, что в языке JavaScript в роли оператора конкатенации выступает плюс. В PHP же, написав плюс, мы в лучшем случае получим на выходе такой результат: 6912 — то есть результат сложения чисел. В худшем случае, если содержание перемен­ных составляли не числа, а текстовые фрагменты, echo выведет в брау­зер ноль. Если переменные содержали как текст, так и числа, текст будет проигнорирован, а числа сложатся:

<?

$abc = "1234a";

$def = "567 8v"; echo $abc+$def;

?>

Выведет в браузер результат 6912. В этом проявляется слабый кон­троль за типов данных в языке PHP.

Есть сокращенный вид конкатенации:

$abc="123";

$abc.="456";

Означает то же самое, что и

$abc="123";

$abc=$abc."456";

Переменные могут быть зарезервированными. Часто употребля­емая переменная $QUERY_STRING считывает из адресной строки текст, следующий за знаком вопроса (при его наличии). Например, если в адрес - ной строке написано: Www. domain. com/index. php? color=silver или просто Www. domain. com/?color=silver, то содержанием переменной $QUERY_STRING будет текст «color=silver» — что не от­меняет того, что в сценарии окажется инициализированной перемен­ная $color, которой уже присвоено значение «silver». (А переменная $HTTP_REFERER, к примеру, включает в себя информацию о той стра­нице, с которой посетитель пришел на данную страницу.)

Если же в адресной строке нет знака вопроса, и строка запроса не образуется, то при ее запросе указанной переменной возникнет ошибка, о чем интерпретатор PHP и сообщит прямо в браузер [Notice: Undefined variable: QUERY_STRING in (адрес файла, где произошла ошибка) on line (номер строки)]. Чтобы написать универсальный код, который вы­водил бы значение переменной $QUERY_STRING только в случае на­личия строки запроса (то есть в случае успешной инициализации этой переменной), следует использовать оператор подавления ошибок @:

If(@$QUERY_STRING)

{

Echo $QUERY_STRING;

}

Здесь мы знакомимся сразу с несколькими вещами: с оператором подавления ошибок @, благодаря которому об ошибке интерпретатор не сообщит, и с условным оператором if, условие после которого за­ключается в круглые скобки (после условия не ставится точка с запятой, как и после объявления имени функции, о чем ниже), а результат вы­полнения условия — в фигурные скобки.

Этот код можно было бы записать и проще:

Echo @$QUERY_STRING;

Наконец, есть специальное средство проверки того, определена ли переменная (функция isset()) и средство разрегистрации пере­менной unset() :

<?

$abc = "12345"; if(isset($abc))

{

Echo $abc; } unset($abc); echo $abc;

?>

В браузер выведется две строчки. Первая будет такой: 12345 . Вторая будет сообщением об ошибке — интерпретатор сообщит, что переменная $abc не определена. К слову, если вы тестируете PHP-сце­нарии на платном сервере, может оказаться, что никаких ошибок и не возникнет, потому что многие владельцы серверов устанавливают мак­симальное подавление ошибок еще на уровне настроек сервера.

Кроме предопределенных переменных, есть еще и константы, в именах которых не используется знак доллара. Среди важных конс­тант можно отметить FILE (имя файла, выполняемого в данный

Момент — по бокам по два символа подчеркивания), PHP_VERSION (угадайте содержимое этой константы), PHP_OS (имя операционной системы, под которой работает PHP — выводится в сокращенном виде, например, WINNT для Windows NT и ветви систем Windows, начиная с 2000 и заканчивая Vista). Вызываются константы оператором echo, как и переменные. Как и переменные, константы можно использовать в со­ставе других строк.

Массивы — это упорядоченные наборы переменных. Имена их тоже начинаются со знака доллара. Есть два типа массивов: списки (ав­томатически нумеруемые массивы, где ключами значений выступают числа от нуля до относительной бесконечности) и ассоциативные мас­сивы (где пары «ключ — значение» записываются в явном виде).

Пример массива-списка:

I $spisok = array("Январь","Февраль","Март","Апрель");

Полностью аналогичной записью будет:

I $spisok = list("Январь","Февраль","Март","Апрель");

При вызове определенного номера элемента на экране будет вы­ведено значение этого элемента массива. Например, чтобы на экране появилась надпись «Март», следует записать:

Echo $spisok[2]; // Двойка вызывает третий эле­мент, потому что нумерация Начинается с нуля

// Все, что записано после двух слэшей и до

// конца строки, считается в PHP комментариями

В квадратных скобках при вызове элемента массива записывает­ся ключ этого элемента: числовой или иного типа.

Ассоциативный массив записывается так:

$assoc = array("Имя" => "Иван","Фамилия" => "Иванов","Год рождения" => "1970");

Теперь, чтобы вызвать нужные данные, следует написать:

Echo $assoc["Фамилия"]." ".$assoc["Имя"];

На экран будет выведен текст: «Иванов Иван». Обратите внима­ние, что пробел — это обычный текст, внедренный в код на PHP, поэ­тому он записан в кавычках. Три отрезка текста объединяются в строку при помощи оператора конкатенации.

Такой «ручной» вызов элементов массива используется очень редко. Такой вызов применяется, например, при динамическом фор­мировании массива. Часто элементы массива вызываются циклически, о чем ниже.

Массивы можно записывать и не в одну строку. Например, для списка правомерной будет и такая запись:

$spisok[] = "Январь";

$spisok[] = "Февраль ";

$spisok[] = "Март";

$spisok[] = "Апрель";

Для ассоциативного массива, где нет автоматической нумерации, построчная запись отличается только явной записью ключей:

$assoc["Имя"] = "Иван";

$assoc["Фамилия"] = "Иванов";

$assoc["Год рождения"] = "1970";

Вызов же элементов массива от формы их записи не меняется. Массивы могут быть многомерными. В них каждый из элементов массива сам является массивом:

$massiv = array();

$massiv[0] = array("1","2","3");

$massiv[1] = array("4","5","6");

В этом случае при вызове

Echo $massiv[1][2];

На экран будет выведено число «6».

Как уже упоминалось, массивы и их циклическая обработка — удобная связка. Рассмотрим несколько примеров. Предположим, что массивы уже инициализированы, так что мы будем использовать в цик­лах именно их.

Простой перебор массива можно осуществить циклом foreach: foreach($spisok as $spisok1)

{

Echo "<p><b>".$spisok1."</b></p>";

}

Если перевести эту запись на русский язык, то получится при­мерно следующее: каждый элемент массива $spisok назначается как значение переменной $spisok1 по очереди, и после этого назначения каждый раз содержимое вновь переназначенной переменной $spisok1 оформляется как отдельный абзац, набранный полужирным текстом. Именно это и получается на выводе.

Равноценной будет запись и с оператором цикла while:

$i=0;

While($i < count($spisok))

{

Echo "<p><b>".$spisok[$i]."</b></p>";

$i++;

}

Здесь пришлось ввести переменную $i, изначально равную нулю. С каждым «оборотом» цикла значение увеличивается на единицу: это совершает оператор инкремента, записывающийся как два плюса под­ряд. Оператор декремента записывается как два минуса и обозначает уменьшение на единицу. При первом проходе цикла вызывается первый элемент массива ($spisok[0], поскольку значение переменной равно нулю). При каждом следующем проходе после увеличения значения $i на единицу вызывается следующий элемент массива. Строка while($i < count($spisok)) в переводе на русский язык обозначает: «пока значение переменной $i меньше длины массива $spisok». Длина мас­сива вычисляется функцией count(), в которую в качестве парамет­ра передается имя массива. Математические операторы используются в PHP почти без изменений (плюс +, минус - , умножение *, деление /, целочисленный остаток от деления %). Из операторов сравнения чаще всего используются == (равно), === (тождественно по значению и типу данных), ! = (не равно) и!== (не тождественно), а также обычные мате­матические <, >, >= и <=.

Кстати, цикл можно прервать на каком-либо элементе: для этого используется оператор break:

$i=0;

While($i < count($spisok))

{

If($i==2) break;

Echo "<p><b>".$spisok[$i]."</b></p>";

$i++;

}

Здесь будет выведено только два первых элемента массива. От­дельные элементы цикла можно пропустить с помощью оператора

Continue:

Foreach($spisok as $spisok1)

{

If($spisok1=="MapT") continue; echo "<p><b>".$spisok1."</b></p>";

}

В этом примере будет пропущено слово «Март», что очевидно. Наконец, еще один вид циклов управляется оператором for:

For($i=0; $i<count($spisok); $i++)

{

$j=$i+1;

Echo "<p>".$j.". <b>".$spisok[$i]."</b></p>";

}

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

Каждый из этих операторов обладает своими удобствами: с ка­ким-то удобно работать, не ориентируясь на числа, с каким-то — как раз оперируя числами. Цикл while позволяет работать с условиями.

С ассоциативными массивами удобнее всего работать циклом foreach — он осуществляет простой перебор, при этом может опери­ровать и ключами, и значениями. Если обратиться к тому ассоциатив­ному массиву, который приводился в качестве примера, то циклический перебор с форматированием можно осуществить так:

Foreach($assoc as $key => $value)

{

Echo "<div>".$key.": ".$value."</div>";

}

В этом случае на экране окажется такая запись:

Имя: Иван Фамилия: Иванов Год рождения: 1970

Работа условных операторов в PHP похожа на работу условных операторов в любом другом языке. Если оператор внедрен в код PHP, то бывает достаточно одного или двух его компонентов: IF («если») и в не­которых случаях ELSE («в остальных случаях»). Часто используется так­же ELSEIF и его синоним ELSE IF. Если используется нестандартный формат записи (о нем чуть ниже), то обязателен также элемент ENDIF (конец условного цикла).

Для примера еще немного забежим вперед. В качестве условий будем использовать дату и время, а точнее — текущее число, обозна­чающее часы. Дата и время выводятся функцией date(), в качестве параметра которой используется метка, уточняющая запрос. Чтобы вы­звать количество часов, используем формат date("H"). В зависимости от получившегося числа на странице выводится приветствие. Самый привычный вид записи с условными операторами таков:

<?

$tempo = date("H"); if($tempo>4 && $tempo<11)

{

Echo "Доброе утро!";

}

Elseif($tempo>10 && $tempo<17)

{

Echo "Добрый день!";

}

Elseif($tempo>16 && $tempo<23)

{

Echo "Добрый вечер!";

}

Else

{

Echo "Здравствуй, полуночник!";

}

?>

Чтобы сценарий в каждой ветке условных операторов не вычис­лял дату и время (экономьте электроэнергию ресурсы), сначала мы вводим переменную, которой единожды присваивается значение — те­кущее количество часов. Затем идет простое сравнение и вывод резуль­тата выполнения условия в браузер.

Тот же самый пример можно записать и так:

<?

$tempo = date("H"); if($tempo>4 && $tempo<11)

{

?>

Доброе утро!

<?

}

Elseif($tempo>10 && $tempo<17)

{

?>

Добрый день!

<?

}

Elseif($tempo>16 && $tempo<23)

{

?>

Добрый вечер!

<?

}

Else

{

?>

Здравствуй, полуночник!

<?

}

?>

Конечно, код получился немного длиннее, но у него появилось одно преимущество: мы можем не использовать оператор echo, а писать как результат условия простой HTML в любом количестве. Очевидно, что таким образом в зависимости от времени суток (и других условий) можно целиком менять содержимое страницы (правда, разумнее просто добавлять какие-то нюансы или менять какой-либо текст). Фигурные скобки, заключающие результат выполнения условий, расположены в правильном порядке, поэтому целостность сценария не нарушается, хотя, строго говоря, тут 5 фрагментов на PHP. Правда, для такой записи более удобным и компактным является следующий формат, не требую­щий фигурных скобок:

<?

$tempo = date("H");

?>

<?if($tempo>4 && $tempo<11):?>

Доброе утро!

<?elseif($tempo>10 && $tempo<17):?>

Добрый день!

<?elseif($tempo>16 && $tempo<23):?>

Добрый вечер!

<?е^е:?>

Здравствуй, полуночник!

<?endif?>

Обратите внимание на двоеточия после условных операторов и на кодовое слово е^1:Е, указывающее на то, что блок условных опе­раторов закончен. Результат выполнения условий записывается опять же в формате HTML.

Если условий несколько, их можно группировать при помощи круглых скобок, не нарушая вложенности:

If(date("H")>12 || (date("H")<12 &&

Date("D")=="Mon"))

{

}

Данное специфическое условие будет выполнено, если на­ступило послеполуденное время (date("H")>12) или (||) — второй вариант условия — все еще первая половина дня и (&&) сегодня поне­дельник (date("D")=="Mon"). То есть какой-то результат будет полу­чен, если истинным будет либо первое условие, либо комплекс из вто­рого и третьего условий (именно комплекс, а не каждое по отдельности), но не иначе (правда, если сегодня понедельник, но время уже после полудня, то условие все равно будет выполнено — только потому, что истинным окажется первое условие, что время послеполуденное, а сце­нарию этого достаточно).

Наконец, условия могут быть вложенными:

If(первое условие)

{

If(второе условие, имеющее смысл только тогда, когда истинно первое)

{

Результат, когда верны и первое, и второе условия }

Else

{

Другой результат, когда верно первое условие, но не верно второе }

Какой-то другой вывод, не зависящий от вложенных условий }

Else

{

Все остальные результаты }

Комментарии тут излишни, кроме одного: вложенность не огра­ничивается ничем, кроме здравого смысла.

Альтернативный синтаксис возможен не только в случае с услов­ными операторами, но также и с циклами:

<?while (логическое выражение):?>

Повторяющийся HTML-код <?endwhile;?>

<?for($i=1; $i<=10; $i++):?>

<p><? echo $i;

?></p>

<?endfor;?>

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

Строка запроса: <?=@$QUERY_STRING?>.

В конце такого употребления не требуется точка с запятой. Функции — чрезвычайно удобное средство один раз написать код, а затем использовать его сколько угодно раз. При этом в функцию можно передавать произвольное количество параметров, которые обра­батываются как переменные, а результат обработки либо возвращается функцией (оператор return) для последующего использования (вывод в браузер или дальнейшая обработка), либо выводится напрямую (опе­ратор echo) в браузер посетителя сайта.

Поясним на примере. Допустим, нам нужно форматировать ка­кой-то текст полужирным и вывести его в виде отдельного абзаца. Ка­кой это текст, неизвестно, потому что он генерируется динамически. Создадим функцию для вывода этого текста в нужном виде на экран.

Сайт выполняет черную работу

4.3

В самом PHP такой функции, конечно, не существует, поэтому приду­мываем функцию сами:

Function bolder($text)

{

Echo "<p><b>".$text."</b></p>";

}

Сначала идет объявление функции; если ей передаются парамет­ры, то они записываются в виде переменных в скобках, и эти перемен­ные затем используются в функции.

Теперь нам осталось в произвольном месте PHP-кода вызвать эту функцию и передать в нее текст:

Bolder("Полужирный абзац");

В месте вызова этой функции будет создан абзац с текстом «По­лужирный абзац», набранный полужирным начертанием. Все пре­дельно просто; единственное, о чем нельзя забывать — что объявление функции и ее описание должно следовать до вызова, иначе возникнет ошибка (дело в том, что PHP анализирует документ последовательно и не может вызвать функцию, которую еще не знает, в отличие, напри­мер, от JavaScript).

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

Function bolder($text)

{

Return "<p><b>".$text."</b></p>";

}

В этом случае, чтобы вывести на экран полужирный абзац, следу­ет напечатать возвращаемое функцией значение оператором echo:

Echo bolder("Полужирный абзац");

При усложнении (относительном, конечно) вывода появляется дополнительная возможность: перед выводом результат работы фун­кции можно обработать другими функциями. Либо записать файл без вывода на экран. Либо сохранить как элемент массива. Например, сле­дующий фрагмент кода:

Echo strlen(bolder("Текст"));

Выведет на экран длину текста «Текст», оформленного тэгами абзаца и полужирного начертания (всего 19 символов), не выводя текст на эк­ран. Не знаю, зачем это нужно. Это только пример. Функции можно на­зывать латинскими буквами, используя символ подчеркивания и циф­ры. Пробелов и иных символов быть не должно. Начинайте названия функций с букв.

Функции могут иметь значения по умолчанию. Это значит, что вызов функции без передаваемых параметров будет обрабатываться с предустановленным в функции значением, а при передаче в функцию значения оно заменит значение по умолчанию:

<?php

Function makecup($type = "чая")

{ return "Принесите чашечку $type"; }

Echo makecup();

Echo такесир("кофе");

?>

Первый оператор echo напечатает в браузер фразу «Принесите чашечку чая», потому что вызов функции произошел без передачи зна­чения, а значит, используется значение переменной $type по умолча­нию. Вызов echo makecup("кофе"); напечатает фразу «Принесите чашечку кофе». Обратите внимание, что переменная употреблена пря­мо внутри обычного текста; такое допускается, если текст заключен в двойные кавычки.

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

Удобство языка PHP в том, что в нем есть несколько сотен уже определенных и описанных функций, которые нужно только правильно вызывать в нужном месте. Например, есть функция str_replace(), аргументами которой являются три параметра: искомый фрагмент тек­ста; фрагмент текста, на который будут заменены все найденные фраг­менты, соответствующие первому параметру; строка, в которой произ­водится поиск и замена. Пример:

Echo str replace("муха","слон","муха");

Этот вызов функции сделает из мухи слона: он обратится к стро­ке «муха» (третий параметр) и заменит в ней все вхождения подстроки «муха» на подстроку «слон». Еще пример:

Echo str replace("я","жа","яркий");

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

Дело в том, что до версии 4.3.0 в PHP не было функции счи­тывания файла в строку. Приходилось использовать обходной путь: join("",File("имя файла")) — функция File() считывает файл построчно и формирует массив, каждый из элементов которого состоит из одной строки файла. Функция join() и ее синоним implode() за­нимаются тем, что «склеивают» любой массив, переданный в качестве второго параметра, с помощью разграничителя, передаваемого первым параметром (в данном случае в кавычках указано пустое значение, зна­чит, строки файла просто склеятся в одну). До сих пор на некоторых хостинг-площадках стоят версии 4.1, а иногда и ниже, что затрудняет использование специализированной функции для чтения файла в стро­ку file get contents("имя файла") , которая появилась в PHP 4.3.0. И если вы готовите сценарии, которые не должны зависеть от суб­версий интерпретатора, то можно прибегнуть к одной уловке, которая заставит работать функцию file_get_contents() на всех версиях:

If(!function exists("file get contents"))

{

Function file get contents($fname)

{

Global $fname;

Return join("",File($fname));

}

}

Суть уловки такова. Проводится проверка на существование функ­ции (function exists("название функции без скобок")), и если функция не определена (символ отрицания — восклицательный знак перед утверждением), то она определяется обычным способом, как и все пользовательские функции. В нее передается параметр, а в те­ле функции переменная объявляется глобальной и далее используется эмуляция этой функции для старых субверсий PHP. Понятное дело, что если функция уже определена (то есть установлена свежая версия PHP), то условие окажется ложным, и дальнейший код этой уловки бу­дет пропущен — но поскольку функция существует и так, она будет вы­полняться в обоих случаях. Можно написать этот код в главном файле или в том, который будет включаться во все остальные, и использовать функцию file_get_contents() безбоязненно. Следует заметить, что такое считывание файла нужно только в том случае, если нужна даль­нейшая обработка строки (например, поиск и замена, использование заданной части строки, иные преобразования), а если нужно просто вы­вести включаемый файл в текущий (это называется: «включить файл»), то можно использовать операторы require или include, после кото­рых в кавычках пишется название файла, который необязательно ле­жит в одной и той же директории, что и текущий файл. Разница между операторами в том, что первый работает быстрее, а второй позволяет серверу не делать лишнюю работу при условно определяемом вклю­чении. Допустим, что в зависимости от какого-то условия включается либо первый, либо второй файл. Если использовать require, то будут прочитаны оба файла, несмотря на то, что одно из условий ложно (хотя на вывод пойдет все же только нужный файл). Если же использовать include, будет прочитан (и выведен) только нужный файл:

If(!$QUERY_STRING)

{

Include "files/glavnaya. php";

}

Else

{

Include str_replace("http://", "", strtolower("files/".$QUERY_STRING.".php"));

}

Рассмотрим сценарий подробнее, поскольку он является (при­митивной, но все же) веб-архитектурой. Главный файл (index. php) вы­полняется в любом случае. Остальные страницы лежат в директории «files». Если строки запроса в адресе не наблюдается, в основной файл включается файл по адресу files/glavnaya. php — это происходит при за­грузке главной страницы сайта. В остальных случаях (если адрес вы­глядит как Www.Domain.Com/7Company или наподобие) включается файл, имя которого до расширения указано в строке запроса (то есть в данном случае будет включен файл company. php из директории files). Если файла не существует, то сообщение об ошибке отсутствия файла подавляет­ся оператором @. Можно написать более гуманный сценарий, где при помощи функции file_exists("имя файла") и вложенных услов­ных проверяется наличие файла, а при его отсутствии выводится дру­желюбное сообщение. Однако строка запроса подвергается санитарной чистке. На всякий случай все символы переводятся в нижний регистр (функция strtolower(), обратная ей называется strtoupper()), а на случай злонамеренных действий в полученном имени файла уда­ляется имя протокола http (на всякий случай можно было бы удалять еще и ftp) — даже если написано HTTP, то и в этом случае эта подстрока отрежется. Дело в том, что при включении файла, чье имя явно пере­дается в строке запроса, можно сфальсифицировать адрес, подставив в качестве имени файла адрес файла на своем сервере. А в этом случае хакер может с помощью своего сервера обратиться к данным на вашем сервере и захватить управление сайтом.

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

Как уже говорилось, в PHP есть масса уже определенных функ­ций, которые имеют жестко определенный синтаксис. Рассмотрим на­иболее употребительные из них; для удобства расположим их по катего­риям: функции для работы со строками, массивами, датой и временем, файлами (в том числе для загрузки файлов) и директориями, почтой, изображениями, базами данных и технологией Cookies. Для упрощения понимания синтаксиса в скобках вместо принятых англоязычных обоз­начений используются интуитивно понятные русскоязычные. В квад­ратных скобках указаны необязательные параметры.

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

Функция strlen(cTpo^) просто возвращает длину передан­ной ей строки в символах. Пригождается, когда требуется извлечь опре­деленное количество символов или переместиться в файле на заданную длину, но при этом заранее длина строки неизвестна.

Функция strpos(cTpo^, искомое) находит в строке пер­вое вхождение искомого (заданного) текста и возвращает номер пер­вого символа искомого в этой строке. Так, strpos("nepe^',"e") вернет число 1 (нумерация, напомню, начинается с нуля). Функция strrpos(строка, искомое) действует так же, но ищет с конца, по­этому strrpos("nepe^',"e") вернет число 3. Широко используется в поисковых системах. Функция strpos() также часто используется, чтобы просто проверить наличие подстроки в строке:

$zapros = @$QUERY_STRING;

If(strpos($zapros,"web")!==false)

{

Echo "Вы находитесь в разделе о веб-дизайне";

}

Функция str_replace(4^, на что, где) выполняет поиск и замену в строке (причем исправляет в строке все вхождения первой подстроки на вторую). Часто применяется для форматирования текста, когда нужно совершить множество преобразований с текстом «на лету», но чтобы при этом текст в файле или базе данных оставался нетронутым. К слову сказать, в качестве второго параметра можно указать пустую строку (то есть просто кавычки без содержимого), чтобы убрать задан­ные элементы (первый параметр) в строке (третий параметр). Не забы­вайте: если вы используете строки и подстроки прямым текстом, заклю­чайте их в кавычка, тогда как для переменных кавычки не требуются. В подстроках можно объединять текст и переменные с помощью точек:

$zapros = @$QUERY_STRING;

$text = file get contents("имя файла");

Echo str replace($zapros, "/".$zapros."/",

$text);

В этом примере, если в тексте указанного файла встретится упо­минание текущей строки запроса, получаемой из адресной строки, все вхождения этой строки в выведенном тексте оформятся слэшами по бокам. Единственный оператор подавления ошибок заставит работать этот пример корректно даже тогда, когда строки запроса не будет су­ществовать. Поскольку в PHP используются интерполируемые сим­волы (например, n для передачи разрыва строки, то есть нажатия клавиши Enter), то их в определенных случаях тоже можно заменять на что-либо:

$text = file get contents("имя файла");

Echo str replace("n", "<br>— ", $text);

В примере переводы строк снабдятся тэгами разрыва строки и ти­ре с пробелом. Интерполируются только символы в двойных кавычках, а если написать эту подстроку в одинарных кавычках, то функция будет искать сочетания обратного слэша и буквы «n» и не найдет их. К слову, для простого преобразования символа перевода строки в тэг <br /> используется уже определенная функция п12Ьг(стро^) .

Функция substr(строка, откуда, длина) возвращает под­строку заданной длины («длина») с указанного номера символа («отку­да»); третий параметр необязателен: если не указать длину, то подстрока будет считываться до конца строки. Можно использовать в сочетании с другими функциями. Например, нужно вывести текст заголовка стра­ницы, но без тэгов заголовка:

$text = file get contents("имя файла"); // Читаем файл в строку

$text2 = substr($text, strpos($text, "<H1>"));

// Обрезаем от первого вхождения тэга <h1>

$text2 = substr($text, 0, strpos($text2, "</ H1>")); // Обрезаем по длине до <h2>

// но в $text2 еще остался тэг <h1>. Убираем все тэги сразу:

$text2 = strip tags($text2); echo $text2;

Функция strip_tags(строка) убирает из строки все тэги. В качестве второго необязательного параметра в кавычках без пробе­лов можно указать тэги, которые останутся после чистки. Функция htmlspecialchars(строка) не убирает тэги, а заменяет спецсим­волы вроде угловых скобок на их мнемонические представления, так что тэги выводятся на страницу как примеры HTML-кода. Функция stripslashes(строка) убирает из строки все слэши, которые авто­матически расставляются сценарием перед кавычками при получении данных из формы. Функция str гереа^строка, число повто­ров) повторяет заданную строку заданное количество раз. Функции strtolower(строка) и strtoupper(строка) переводят все сим­волы строки в нижний и верхний регистры соответственно.

Если файлы на сайте используются вместе, но набраны в разных кодировках, то при совместном использовании этих файлов (например, при включении один в другой) может возникнуть неприятный эффект, когда часть текста преобразовывается в нечитаемые символы. Два пути решения этой проблемы зависят от того, в какой кодировке набраны тексты. Если это одна из четырех традиционных кириллических кодиро­вок (Windows 1251, KOI8-R, ISO, MAC), то при переводе текста из одной в другую достаточно вызвать функцию convert_cyr_string ( строка, из, в), где второй и третий параметры — сокращенные наименования указанных кодировок (w, k, i, m), указываемые в кавычках. Однако, если используется юникод, где система расположения символов принци­пиально отличается от четырех названных, то используется функция iconv(из, в, строка)— в ней не только другой порядок следования параметров, но и другой формат записи кодировок. Например, чтобы перевести строку $str1 из кодировки Windows 1251 в юникод, следует написать:

$str1 = iconv("cp1251", "UTF-8", $str1);

К сожалению, поддержка модуля iconv реализована не на всех хостинг-площадках, поэтому перед покупкой хостинга следует интере­соваться, все ли нужные вам модули установлены на сервере наряду со стандартным PHP

Массивы можно не только записывать и считывать при помощи циклов или «вручную», но и производить над ними другие операции.

Функция count(Mac^B) подсчитывает элементы массива и возвращает итоговое количество. (Обычно функции, возвращающие какое-либо значение, ведут себя так, как если бы в их теле находился оператор return, а не echo — то есть чтобы напечатать полученное в результате выполнения функции значение, следует вызвать функцию с параметром оператором echo, в ином случае в браузер ничего не вы­ведется; это дает то преимущество, что перед выводом данные можно обработать.)

Функция join(разделитель, массив) сливает все эле­менты массива в одну строку. Ее синонимом является функция implode(разделитель, массив) — она делает то же самое, — а ан­тонимом — функция explode(разделитель, строка). Последняя анализирует переданную строку, находит в ней фрагменты, соответству­ющие подстроке «разделитель», выбрасывает разделители, но в местах разделителей создает границы между элементами массива, который со­здается функцией. Иными словами, код

$schet = explode(", ", "Первый, второй, третий");

Дает тот же результат, что и

$schet = аггау("Первый", "второй", "третий");

С той только разницей, что вручную создавать массив не требу­ется. Фрагмент с функцией explode() разбивает строку по подстроке «запятая пробел» и формирует массив из трех элементов.

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

Функция asort(массив) сортирует массив в алфавитном (или логическом, если это не буквы) порядке. Если массив ассоциативный, связи «ключ — значение» сохраняются. Функция arsort(массив) сортирует массив в обратном порядке (с «10» до «1», с «Я» до «А») — ведет обратный отсчет. Сортировка ведется по значениям, то есть если клю­чи шли, например, в алфавитном порядке, то этот порядок нарушается. Поскольку у ассоциативных массивов нет явных ключей, то происходит перенумерация элементов массива.

Сайт выполняет черную работу

4.3

Сортировка по ключампроизводится функциями ksort(Mac^B) (алфавитно-логический порядок) и к^о^(массив) — обратный по­рядок. Связи между ключами и значениями, если это ассоциативный массив, не нарушаются.

Если требуется применить более сложный алгоритм сортировки, заданный в заранее определенной функции, то применяются функ­ции uksort(Mac^B, "название функции без скобок") или uasort(Mac^B, "название функции без скобок") — для сор­тировки по ключам или значениям соответственно.

Если требуется отсортировать не ассоциативные массивы, а спис­ки, то лучше применять функции sort(массив) и ^о^(массив) — для прямой и обратной сортировки. Функция usort (массив, "на­звание функции без скобок") сортирует списки с использованием функции.

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

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

Функция array геуегсе(массив) переворачивает массив в обратном порядке. То есть для ее вызова необходимо сделать следую­щую запись:

$abc = аггау(тут записаны элементы массива);

$abc = array reverce($abc);

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

Функция array АКр(массив) меняет местами ключи и значе­ния: значения становятся ключами, а ключи — значениями. Функции array keys(массив) и array values(массив) возвращают мас­сивы, содержащие ключи (в первом случае) и значения (во втором) ис­ходного массива.

4

Программирование

Функция in array(элемент, массив) возвращает true (ис­тину) или false (ложь) в зависимости от того, присутствует ли элемент в данном массиве или нет.

Функция array merge(массив 1, массив 2, ...) сливает произвольное количество массивов, указанных в параметрах, в один, и возвращает результирующий массив.

Функция array slice(массив, номер элемента, [дли­на]) возвращает часть массива, начиная с указанного номера элемента. Если не указать длину результирующего массива, то возвращен будет массив с указанного элемента до конца исходного массива.

С помощью функции Unset() с указанием элемента массива по ключу можно удалить этот элемент. Напротив, с помощью функции array р^Ммассив, новый элемент 1, новый элемент 2, ...) в конец массива добавляются новые элементы. Функция же array unshift(массив, новый элемент 1, новый элемент 2, ...) добав­ляет новые элементы в начало массива. Функция array pop (массив) просто удаляет последний элемент массива без прямого указания на него, но возвращает этот элемент в качестве результата. Функция array shift(массив) делает то же самое с первым элементом массива.

Для быстрого создания диапазона чисел используется функция range(первое число, последнее число).

Основная функция для работы с датой и временем — date(«метки»), в качестве значения которой используются метки, обозначающие разные представления времени. Основные метки пере­числены ниже:

A Ante meridiem или Post meridiem в нижнем регистре (am или pm) A Ante meridiem или Post meridiem в верхнем регистре (AM или PM)

D День месяца, 2 цифры с ведущими нулями (от 01 до 31)

D Сокращенное англ. наименование дня недели, 3 символа (от Mon до Sun)

F Полное английское наименование месяца (от January до December)

G Часы в 12-часовом формате без ведущих нулей (от 1 до 12)

G Часы в 24-часовом формате без ведущих нулей (от 0 до 23) h Часы в 12-часовом формате с ведущими нулями (от 01 до 12)

H Часы в 24-часовом формате с ведущими нулями (от 00 до 23) i Минуты с ведущими нулями (00 to 59)

I Признак летнего времени — 1, если дата соответствует летнему времени, или 0 j День месяца без ведущих нулей (от 1 до 31) l Полное наименование дня недели (от Sunday до Saturday)

L Признак високосного года — 1, если год високосный, иначе 0

304

Сайт выполняет черную работу

4.3

M Порядковый номер месяца с ведущими нулями (от 01 до 12)

M Сокращенное наименование месяца, 3 символа (от Jan до Dec) n Порядковый номер месяца без ведущих нулей (от 1 до 12)

O Разница с временем по Гринвичу в часах (Например: +0200) r Дата в формате RFC 2822 (Thu, 21 Dec 2000 16:01:07 +0200) s Секунды с ведущими нулями (от 00 до 59)

S Английский суффикс порядкового числительного дня месяца,

2 символа — st, nd, rd или th. Применяется совместно с j t Количество дней в месяце (от 28 до 31)

T Временная зона на сервере (EST, MDT)

U Количество секунд, прошедших с начала Эпохи Unix (1 января 1970, 00:00:00 GMT) w Порядковый номер дня недели — от 0 (воскресенье) до 6 (суббо­та)

W Порядковый номер недели года по IS0-8601, первый день неде­ли — понедельник (добавлено в PHP 4.1.0) [например: 42 (42-я неделя года)]

Y Порядковый номер года, 4 цифры (1999, 2003) y Номер года, 2 цифры (99, 03)

Z Порядковый номер дня в году, нумерация с нуля (от 0 до 365)

Z Смещение временной зоны в секундах. Для временных зон запад­нее UTC это отрицательное число, восточнее UTC положитель­ное (от-43200 до 43200)

Используя даты и время по отдельности, можно получать числа и строки. Если возвращаются числа, то с ними можно производить ма­тематически операции. Строки и числа можно конкатенировать. В ка­вычках в качестве параметра функции допускаются не только метки, но и форматирующие и разделяющие элементы:

Echo date(”d. m H:i”);

В результате выполнения кода на экране появится надпись вида: «02.11 23:17» (с поправкой на текущее время, конечно). То есть знаки препинания и прочая информация, не совпадающая с зарезервирован­ными метками, используемыми в функции, будет выводиться как есть. В сценарии можно назначить переменную, отвечающую за вывод време­ни, и записывать содержимое этой переменной в файл или базу данных при разработке чата, форума, блога, новостной ленты и прочих типов сайтов, для которых важны указания на дату и время создания записи.

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

Проверить файл на существование можно с помощью функции file exists (файл) — функция возвращает значения true или false.

С двумя функциями мы уже познакомились ранее: это функ­ция file_get_contents(имя файл) , считывающая файл как строку, и Еі1є(имя файла) , нужная для того, чтобы занести каждую строку файла в отдельный элемент массива. Напомню, что первая из упомяну­тых функций работает не во всех версиях PHP, поэтому следует соблю­дать осторожность.

Аналогичная функция для записи в файл — file_put_contents (файл, данные) — появилась только в PHP 5. До этого приходилось использовать такую последовательность команд:

$fp=fopen(файл,"w+");

Flock($fp, LOCK_EX);

Fwrite($fp, данные);

Flock($fp, LOCK_UN);

Fclose($fp);

Первая строка открывает файл на запись (параметр "w+", в отли­чие от "a+", который позволяет дописывать данные к уже существую­щим в файле) и назначает идентификатор открытого файла (в данном случае переменная $fp). Имя файла можно передавать как напрямую, в кавычках (и даже с указанием пути, если он расположен в другой ди­ректории), так и посредством переменной. Вторая строка блокирует файл от записи другими процессами — то есть вплоть до отмены этой блокировки (четвертая строка) в файл может производить запись толь­ко данный сценарий, вызвавший блокировку. Третья строка производит собственно запись данных в файл. Пятая строка закрывает файл.

Но предположим, что запись требуется производить часто разны­ми фрагментами сценария и в разные файлы. Каждый раз писать эти пять строк кода как минимум неэкономно; кроме того, всегда спра­ведливо утверждение: больше кода — больше потенциальных ошибок. Проще один раз определить функцию и пользоваться ей неограничен­но, сообщая ей только два параметра: имя файла и записываемые дан­ные. Предположим, что нам неизвестно, под какой версией PHP наш сценарий собирается работать. Как в случае с file_get_contents() (версионная совместимость которой больше), мы можем написать фун­кцию, которая будет проверять, существует ли функция file_put_ contents(), и если нет, то будет описана пользовательская функция:

If(!function exists("file put contents"))

{

Function file put contents($fname,$data)

{

$fp=fopen($fname,"w+");

Flock($fp, LOCK_EX);

Сайт выполняет черную работу

4.3

Fwrite($fp,$data); flock($fp, LOCK UN); fclose($fp);

}

}

Определив функцию один раз, можно постоянно пользоваться ей в дальнейшем. Теперь для записи данных в файл достаточно следующей строчки:

File put contents("имя файла", данные);

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

$filename = "название файла";

$data = "какие-то данные, которые будут записаны в файл";

$ex data = file get contents($filename);

File put contents($filename, $data.$ex data);

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

File put contents($filename, $ex data.$data);

К слову будет сказать, что, если файл не существовал, то он со­здастся.

Если требуется автоматически записать путь к файлу, то можно использовать функцию dimame(файл). В качестве параметра ей удоб­но передавать константу FILE, которая хранит в себе полный путь к файлу:

Echo dirname( FILE ) ;

Схожая функция basename(файл) возвращает имя файла, «очи­щенное» от его пути. Впрочем, в функции можно передавать и названия файлов — главное, чтобы они были в «области видимости» сценариев.

Две функции связаны с датой. Одна — fileatime(имя фай­ла) — сообщает обо времени последнего обращения к файлу, а вторая — ііієпЛіпіє^мя файла) — время последнего обновления файла (если он не обновлялся — то время создания). Обе эти функции имеют вывод,

Малопригодный для человеческого восприятия, поэтому удобнее быва­ет отформатировать возвращаемое значение функцией date():

Echo date ("F d Y H:i:s.", filemtime(имя файла));

Функция filesize( имя файла) сообщает размер файла в байтах. Язык PHP позволяет использовать функции, схожие с функциями операционных систем, а именно — копирование, перемещение, пере­именование и удаление файлов. Функция сору(один файл, другой файл) копирует один файл и создает другой с таким же содержанием. Функция ^пап^старый файл, новый файл) удаляет старый файл, но поме­щает его содержимое в новый. Таким образом, эта функция обслуживает и переименование, и перемещение файлов, ведь в качестве параметров мож­но указать не просто имена файлов, а имена с путями к ним. Так, если

Rename("1.txt","2.txt");

Переименует файл «1.txt» в «2.txt», то

Rename("1.txt","abcd/1.txt");

Переместит файл «1.txt» из текущей директории в директорию «abcd».

Функция ипЫпк(файл) просто удаляет файл.

Работу с директориями логичнее будет рассматривать сразу на конкретных примерах. Директории средствами PHP в первую оче­редь можно просматривать, создавать и удалять.

Допустим, у нас есть директория «catalogue» в корневой директо­рии сайта. Чтобы прочитать ее и вывести список файлов и вложенных директорий в браузер, потребуется следующий фрагмент кода:

$direktoria = "указываем директорию"; chdir($direktoria);

$opdir = opendir($direktoria); while(($item = readdir($opdir))!=false)

{

If($item=="." || $item=="..") continue;

$item arr[] = $item;

}

Sort($item arr); foreach($item arr as $val)

{

Echo '<p>'.$val.'</p>';

}

Сайт выполняет черную работу

4.3

Функция chdir(директория) заставляет сценарий перемес­титься в нужную директорию. Функция opendir(директория) от­крывает директорию для чтения, при этом можно назначить идентифи­катор для открытой директории (в данном случае переменная $opdir); этот идентификатор будет использоваться в дальнейшем.

Далее следует довольно сложная конструкция: проверка на от­сутствие пустого значения (!=false) переменной $item, в качест­ве значения которой каждой раз назначается содержимое прочтения очередного элемента (readdir()) директории, указанной идентифи­катором $opdir. Для назначения приоритета выполнения операций используется группировка при помощи круглых скобок. И вся эта про­верка проводится для работоспособности цикла while, каждый «про­гон» которого считывает новый элемент директории и заносит назва­ния этих элементов в массив $item arr для последующей обработки.

В каждой директории есть два элемента, которые нужно пропус­тить (continue) — это указатель текущей директории (точка) и ука­затель на родительскую директорию (две точки). Ценной информации они не несут, а могут использоваться только для навигации.

После прочтения всей директории у нас оказался неупорядочен­ный массив $item arr, который сортируется по алфавиту функцией sort(). Затем остается только циклом вывести отдельными абзацами название каждого элемента директории. Сценарий можно усложнить, разделив вложенные директории и файлы: для этого можно применить функцию is dir(файл или директория), которая возвращает true или false в зависимости от того, является ли элемент директорией или не является. Разумеется, названия файлов директории нужны не только для вывода, но и для дальнейшей обработки. Например, каждый файл можно снабдить ссылкой.

Чтобы создать директорию, нужно два компонента. Во-первых, средство для передачи сценарию названия будущей директории, а во - вторых, сам сценарий. Средство для передачи — это обычная форма, где есть текстовое поле для ввода названия:

<input type="text" name="act creadir" />

Имя «act creadir» в сценарии будет воспринято как иници­ализация переменной $act creadir. Сценарий мы сразу усложним тем, что русские буквы (мало ли кто будет вводить название) и пробелы будут заменяться на нужные символы.

$translitters = Array(" "=>" ”, ")"=>" ”,

"("_ >" " "—"____ >" " " "_____ >" " "а"____ >"a" "б"____ >"b"

"B"=>"v", "г"_>"д", "д"_>"5", "е"_>"е", "ё"_>'^о",

'^"_>"zh", "3"_>"z", '^"_>"i", '^"_>"j", "к"_>"к",

'о->"о'

подпись: 'о->"о'

"п"=>"р",

подпись: "п"=>"р","л"=>"1", "м"=>"т", "н"=>"п",

"р"=>"г", "с"=>"s",

"x"=>"h", "ц"=>"с",

"ъ"=>"j", "ы"=>"у", "я"=>"ja", "А"=>"а'

"т"=>'^", "у"=>"и", "ф"=>"f",

"4"=>"ch", "ш"=>"sh", "щ"=>"sch",

' э"=>"е", "ю"=>"ju",

"Б"=>"ь", "B"=>"v", "Г"=>"д",

"Д"=>"d", "Е"=>"е", "Ё"=>'^о", "Ж"=>"zh", "3"=>"z",

"M"=>"i", "^"=>"j", "К"=>"к", ..Л"=>"1", "M"=>"m",

"H"=>"n", "О"=>"о", "П"=>"р", "P"=>"r", "C"=>"s",

"T"=>"t", "У"=>"и", "ф"=>"f", "X"=>"h", "Ц"=>"с",

"4"=>"ch", "Ш"=>"sh", "m;"=>"sch", "Ъ"=>"j", "Ы"=>"у",

,,Ь"=>м »1

подпись: ,,ь"=>м »1

"Э"=>"е"

подпись: "э"=>"е""Ю"=>"ju", "Я"=>"ja");

If(@$act creadir)

{

Foreach($trans1itters as $k=>$v) // Заменяем

Кириллицу на латиницу {

$act creadir = str replace($k,$v,$act creadir);

}

Mkdir($act creadir,0777); chmod($act creadir,0777); echo '<р>Директория «'.$act creadir.'» создана<р>';

}

Проанализируем сценарий.

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

В самом сценарии, который выполняется только если значение полученной переменной не пустое (if (@$act_creadir)), сначала циклом все запрещенные символы в полученном имени заменяются на разрешенные, и только затем создается (mkdir ()) директория с именем, полученным в результате преобразования содержания пере­менной $act_creadir. В этой же функции прописываются права доступа (0777 означает полный доступ). Однако этого недостаточ­но: обычно даже при таком вызове функции права на запись в ди­ректорию получает... сервер. Чтобы выйти из положения, следующей строкой (chmod($act_creadir, 0777)) изменяем права доступа на правильные. И в конце выводим извещение об удачном исходе эк­сперимента.

Удаление директорий происходит не функцией Unlink(), как у файлов, а функцией ш^^директория). Указывать файл для удале­ния в форме лучше всего скрытым полем, находящимся рядом с именем

Файла и кнопкой «Удалить» (обычная кнопка для оправки формы, но параметр value приравнивается к слову «Удалить» для наглядности):

<input type="hidden" name="act del" уа1ие="имя директории" />

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

If(@rmdir($act del))

{

Echo '<р>Директория удалена</р>';

}

Else

{

Echo '<р>Какая-то ошибка. Вероятно, директория не пуста. Сначала удалите из нее файлы</р>';

}

Можно модифицировать этот сценарий. Во-первых, при удале­нии непустой папки можно предварительно открывать ее, циклически удалять все файлы в ней, а только затем удалять саму. В этом случае сооб­щение об ошибке вызывать не придется. Во-вторых, можно создать сис­тему уведомлений. Дело в том, что пользователь может удалить файл по ошибке: нажать не ту кнопку, что хотел, нажать кнопку случайно... Пос­ледствия могут быть плачевными. Алгоритм сценария с уведомлениями может быть таков: «если нет дополнительного подтверждения, запраши­ваем удаление еще раз, предоставляя возможность отказаться, а в случае подтверждения посылая дополнительный параметр; если дополнитель­ное подтверждение (этот параметр) получено, директория удаляется». Наконец, с помощью дополнительный полей, настраивающих сцена­рий, можно давать пользователю возможность выбора: удалять непустые директории или нет, запрашивать подтверждения или нет.

Мы должны изучить еще одну важную возможность PHP: загруз­ку пользовательских файлов. Файлы можно не только создавать на сер­вере или копировать, но и получать извне. Для функционирования сце­нария, который позволяет осуществлять загрузку, нужна форма, чтобы указать, какой файл на жестком диске нужно выбрать для копирования. Эта форма должна обладать двумя особенностями. Во-первых, форма должна обладать атрибутом enctype="mu1tipart/form-data", ко­торый позволит отправлять на сервер не только текст, но и более слож­ные данные. Во-вторых, для выбора файла требуется особый тэг <1пр^ type="file" пате="имя поля" />. Под именем поля понимается обычное имя, которое мы присваиваем полям разных типов в форме: это имя станет переменной в сценарии, принимающем и обрабатыва­ющем файл.

Рассмотрим сценарий, который не только будет загружать файл, но и предварительно обрабатывать его имя (сокращать длинные имена, транслитерировать русские буквы, уничтожать пробелы и другие запре­щенные символы в именах файлов), а также интеллектуально относить­ся к файлам, чьи имена совпадают с именами уже загруженных файлов. Кроме того, следует реализовать загрузку в разные пользовательские директории (организованные по типу данных).

Код формы в этом случае примет такой вид:

<^гт method="post" ас^оп="адрес сценария" enctype="multipart/form-data">

Загрузка в: ^е1е^ пате="^о^е of ^^ег"> <ор^оп value="docs">Документы</option>

<ор^оп value="images">Изображения</option> <ор^оп value="archives">Архивы</option>

<option value="media">Мультимедиа</option>

<option value="rest">Разное</option>

<^е1е^>

<input type="file" name="nfname" />

<р>При совпадении имен:

<Ьг /><input type="radio" name="samename" id="samename2" value="zam" checked><label for="samename2"> Заменить файл новьшК/^Ье^

<Ьг /><input type="radio" name="samename" id="samename1" value="men"><label for="samename1"> <span title="К имени файла до расширения автоматически прибавляется 1, или 2, или 3 и т. п. до тех пор, пока имя не окажется уникальным для данной директории">Мод ифицировать</span> имя нового файла</^Ье1>

</р>

<input type="submit" value="Загрузить" onClick="this. value='Загружается...'">

</form>

В начале формы пользователь получает возможность выбора директории, куда он будет загружать файл. Сценарию передадутся ре­альное название директории, тогда как пользователь видит в списке русскоязычные наименования, соотносящиеся с именами директорий только по смыслу. Естественно, эту часть можно реализовать как угодно. Можно даже оставить пользователю поле для ввода имен директорий, если он знает структуру директорий сайта. (Из этого поля или списка сценарий должен получать переменную $choice_of_folder, пото­му что список мы назвали «choice_of_folder».) Главное поле, ко­нечно, то, которое мы назвали «nfname» — тэг <input type="file" пате="имя поля" /> отображает в окне браузера строчку, в которой будет записан адрес файла на жестком диске, и кнопку «Обзор» (в ан­глоязычных браузерах «Browse»). Для некоторого изящества я снабдил переключатели («радиобаттоны») так называемыми «лейблами», когда щелчок по соседнему тексту имеет тот же эффект, что и щелчок по са­мому переключателю, а кнопку «Загрузить» эффектом, когда после на­жатия текст на ней меняется на текст «Загружается...». Слово «Модифи­цировать» снабжено всплывающей подсказкой.

Сам сценарий выглядит так:

I

L

S

N

A

R

T

$

Tters

= Array("

"_ >1

_", ")

1 II II

> _ ,

'('

=>

II II

II II

II II

> _ ,

II II II II

, > ____ ,

II _ II

"а"

=>"a",

"6"=>"b",

'в'

=>

HpH

II

V

"д"=>"d",

"е"

=>"e",

"ё"=>"jo",

'ж'

=>

''zh''

, '3

"=>"z"

, "и"=>"i"

, "й

II II -1 II

>j,

"к"=>"к",

"л"

=>

II "I II 1 ,

''м''

=>"m",

"н"=>"п",

"о"

=>"o",

"n"=>"p",

"р"

=>

II у - II r,

'с'

=>"s",

"T"=>"t",

"у"

=>"u",

'^"=>"f",

'х'

=>

''h'',

"ц"

=>"c",

Ј

=

V

C

И

, "ш

"=>"sh'

"щ"=>"sch",

'ъ'

=>

М м

J,

"ы"

=>"y",

II r II V. II II

Ь => r

"э" =

>"e", "

^"=>"ju",

"я"

=>

"ja"

, 'А

"=>"a"

, "Б"=>"Ь"

, "В

"=>"v",

II - p II II II

I >y,

'Д'

=>

"d",

"Е"

=>"e",

'^"=>"jo"

, "Ж

"=>"zh'

"3"=>"z",

'И'

=>

II - I II i,

"Й"

=>"j",

"K"=>"k",

"Л"

=>"1",

"M"=>"m",

'Н'

=>

"n",

'О'

=>"o",

"П"=>"р",

"Р"

=>"r",

"C"=>"s",

'Т'

=>

''t'',

'У'

=>"u",

"ф"=>"f"r

"Х"

=>"h",

"Ц"=>"с",

'Ч'

=>

"ch"

, "Ш

"=>"sh

", "Щ"=>"3

Ch",

"Ъ"=>'

' j", "Ы"=>"у",

'Ь'

=>

II II

"Э" =

>"e",

"Ю"=>"ju",

"Я"

=>"ja")

;

If(@$nfname)

{

$newname = basename($HTTP POST FILES['nfname'] ['name']);

// Определяем имя и формат файла $fnymn = substr($newname,0,strrpos($newname,".")); $ftype = substr($newname, strrpos($newname,".")+1); $fnymn = strtolower($fnymn);

$ftype = strtolower($ftype);

If(strlen($newname)>2 8) // Сокращаем имя длинных

Файлов {

$fnymn = substr($fnymn,0,25);

}

Foreach($translitters as $k=>$v) // Заменяем

Кириллицу на латиницу {

$fnymn = str replace($k,$v,$fnymn);

}

$newname = $fnymn.,.,.$ftype;

If(file exists($choice of folder.'/'.$newname))

// Если такой файл уже есть {

If($samename=="men")

{

$п=1;

While(file exists($choice of folder.'/'.$newname)) {

$newname = $fnymn.$n.,.,.$ftype; $п++;

}

$addcommentfile = ". Имя загруженного файла модифицировано, поскольку файл с исходным именем уже есть на сервере.";

}

Else

{

Unlink($choice of folder.'/'.$newname); $addcommentfile = " на место файла с аналогичным именем.";

}

}

Else

{

$addcommentfile = ".";

}

Copy($nfname,$choice of folder.'/'.$newname);

If($choice of folder==".")

{

$choice of folder = "корневая";

}

Echo '<p>&nbsp;</p><p class="success">Файл успешно загружен под именем «'.$newname.'» в директорию «'.str replace("./","",$choice of folder ).'»'.$addcommentfile.'</p><p>&nbsp;</p>';

}

В начале сценария приводится тот же ассоциативный массив, ко­торый использовался в сценарии создания директорий для того, чтобы преобразовывать кириллицу в именах в латиницу и заменять недопус­тимые символы допустимыми. Если эти два сценария используются в одном файле, то массив можно привести только один раз перед этими сценариями, а можно вообще вынести в отдельный файл наряду с дру­гими повторяющимися фрагментами кода, а при необходимости вклю­чать в нужный файл. В данном сценарии массив будет использоваться по назначению тем отрезком кода с циклом foreach, который помечен комментарием «Заменяем кириллицу на латиницу».

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

Имя и формат файла определяются простым разбиением пере­данного имени файла на две части, причем разделителем считается пос­ледняя точка: ее находит функция strrpos(). Для имени и расшире­ния файла назначаются переменные, содержимое которых переводится в нижний регистр (strtolower()). Сокращение длинных имен фай­лов производится с помощью функции substr().

После проведения этих операций имя файла и расширение опять объединяются.

Если файл с полученным именем уже есть, выбор дальнейших действий сценарием производится в зависимости от того, что выбрал пользователь: замену файла или генерацию нового имени для загружа­емого файла. Если выбрана замена файла, то файл с таким же именем на сервере удаляется (Unlink()), в противном случае имя модифици­руется. В цикл заключается добавление к имени файла до точки с рас­ширением единицы, двойки и т. п., пока имя файла не окажется уни­кальным — каждый раз проводится проверка файла с новым именем на наличие на сервере.

И только после этого производится копирование файла с окон­чательно сформированным именем в выбранную директорию, о чем сценарий и сообщает пользователю, добавляя подробности, если они требуются.

Если подобный сценарий пишется для сайта, которым будут поль­зоваться люди, желающие минимально заботиться о порядке на сайте,

То можно модифицировать сценарий, интеллектуализировав его: сце­нарий по расширению файла определяет тип данных и загружает файл в нужную директорию, сообщая пользователю, куда помещается файл. Например, если значением переменной $ftype окажутся jpg, jpeg, gif, png и некоторые другие, то файл попадет в директорию «images», а если doc, rtf, pdf, txt, odt — то в директорию «docs».

Функция для работы с почтой в PHP называется mail(). В ка­честве параметра она принимает электронный адрес получателя, тему, текст письма и электронный адрес отправителя. По каким-либо при­чинам письмо не может быть отправлено; нечестно было бы сообщать в этом случае пользователю, что все прошло успешно. Поэтому факт от­правки почты можно сделать условием внутри условного оператора:

If(@$yourletter!=false)

{

If(mail("адрес@получателя. ru",stripslashe s(@$yoursubj),stripslashes($yourletter),"From: "".$youremail."" <".$youremail.">"))

{

Echo "<В>Письмо успешно отправлено. Вы можете написать еще одно:</В>";

}

Else

{

Echo "Письмо не отправлено. Попробуйте еще раз:";

}

}

Важно только записать правильный адрес получателя (обычно это владелец сайта; адрес, разумеется, можно передавать в функцию и переменной) и назначить правильные имена полям формы, которые будет заполнять отправитель письма перед нажатием кнопки «Отпра­вить»: для данного примера поля должны называться «yourletter» (основное поле для текста письма), «yoursubj» (тема сообщения) и «youremail» (электронный адрес отправителя). Без текста в основ­ном поле письмо не отправится.

Эта функция достаточно часто используется, если необходимо скрыть свой электронный адрес. Таким образом частично решается проблема спама: ваш адрес узнают только те, кому вы решите ответить. Кроме того, это часто оказывается удобным для посетителя сайта: ему не нужно загружать свой почтовый ящик, чтобы отправить две строчки владельцу сайта.

Язык PHP позволяет создавать изображения в форматах JPG, PNG, GIF и других, редактировать их и выводить в браузер.

Чтобы работать с изображениями с помощью PHP, необходимо иметь библиотеку функций изображений GD. Обычно она установлена на сервере в составе базового пакета PHP, но если для вас важна такая функциональность, стоит ознакомиться с пакетами, предоставляемыми хостером, еще до заказа тарифного плана.

Для начала рассмотрим пару примеров.

Функция getImageSize() в качестве входного параметра при­нимает имя (адрес) изображения и сообщает размеры изображения, причем заносит их в массив. Первый элемент этого массива выводит данные в таком формате:

Width="400" height="123"

Это достаточно удобно при динамическом формировании тэга <img>. Представим такую ситуацию: в базу данных сайта какой-либо газеты загружается очередная статья (она следует отдельной записью, а значит, имеет уникальный идентификатор). Одновременно загружа­ется изображение в директорию «images», причем изображений может быть несколько. При загрузке имя файла изображения не обрабатывает­ся, а целиком заменяется, соответствуя номеру статьи — идентификато­ру в БД. Поскольку мы решили, что изображений может быть несколько, то формат названия графических файлов примем такой: «идентифи - KaT0p_H0Mep. jpg», например, 241_1.jpg, 241_2.jpgи т. п. Отведем для графики место на странице и напишем небольшой сценерий:

<?

$i = "1";

$img id = идентификатор статьи; while(file exists($search img = "images/".$img id."_".$i.".jpg"))

{

$dimens = getImageSize($search img); echo '<p><img src="/'.$search img.'"

'.$dimens[3].' а^="Иллюстрация '.$i.'" /></p>';

$i++;

}

?>

Изначальное значение номера иллюстрации к статье, естествен­но, — 1. В цикле это значение прибавляется оператором инкремента ++. Цикл действует до тех пор, пока существуют файлы (file_exists() ) запрашиваемых изображений. В области аргументов в функции провер­ки наличия файла одновременно назначается переменная и сообщается ее содержимое — адрес файла. Это позволяет не повторять адрес файла в дальнейшем, а использовать переменную и при чтении размеров изоб­ражения, и при выводе изображения на экран. Переменная $dimens — это массив, куда заносятся данные о размере изображений, причем нас интересует только четвертый элемент массива ($dimens[3] ). Далее тэг строится из фрагментов. Тэги и параметры (кроме размеров) пишутся «прямым текстом», в качестве адреса файла используется содержимое переменной $search_img, генерирующееся заново при каждом про­ходе цикла, первый элемент массива, содержащего информацию о раз­мерах изображения, включается целиком, а в качестве номера изобра­жения используется переменная $i.

В качестве альтернативного текста можно использовать не такие безликие подписи — например, заголовок статьи, ближайший подзаго­ловок и т. п.

Этот пример только «читал» информацию об изображении. Во втором примере изображение будет редактироваться сценарием:

<?

// Подготавливаем почву: выясняем расширение, его и имя — в нижний регистр

$newname = нужное изображение;

$fnymn = substr($newname,0,strrpos($newname,".")); $ftype = substr($newname, strrpos($newname,".")+1); $fnymn = strtolower($fnymn);

$ftype = strtolower($ftype);

// Создание «превьюшек» только для расширений JPG и JPEG

If($ftype=="jpg" || $ftype=="jpeg")

{

$src=imagecreatefromjpeg(,images/'.$newname); $props = getImageSize('images/'.$newname);

$propsw = $props[0];

$propsh = $props[1];

$propskoeff = round($propsw/150);

$propshnew = round($propsh/$propskoeff); $dst=imagecreatetruecolor(150,$propshnew);

// Копирование картинки из оригинальной в уменьшенную

Imagecopyresized($dst, $src, 0, 0, 0, 0,

ImageSX($dst), ImageSY($dst), ImageSX($src), ImageSY($src));

Imagejpeg($dst,'images/'.str replace('.',' min.',$newname),100);

}

?>

После того, как имя файла оказалось разбито на собственно имя и расширение, сценарий проверяет: если расширение файла — .jpg или .jpeg, то создается уменьшенная копия картинки с именем, которое включает подстроку «_min» после имени исходного файла, но до точки с расширением. Ширина конечного изображения — 150 пикселей, вы­сота вычисляется так, чтобы пропорционально соответствовать ширине.

Большой набор функций, посвященных работе с изображениями, можно найти по адресу Www. php. su/functions/?cat=image.

В настоящее время PHP поддерживает работу со следующими ба­зами данных: Adabas D, Ingres, Oracle (OCI7 и OCI8), dBase, InterBase, Ovrimos, Empress, FrontBase, PostgreSQL, FilePro (только чтение), mSQL, Solid, Hyperwave, Direct MS-SQL, Sybase, IBM DB2, MySQL, Velocis, Informix, ODBC, Unix dbm. Чаще всего хостеры (при предоставлении услуги «виртуальный хостиинг») предлагают использование только одного типа БД — а именно MySQL (жаргонизм «мускул» обозначает именно эту базу данных).

Аункцией для соединения с MySQL является mysql_connect(), ко­торая подключает скрипт базе и выполяет авторизацию пользователя:

Mysql connect (имя хоста, имя пользователя, пароль);

Функция возвращает идентификатор соединения, через кото­рый осуществляется вся дальнейщая работа. Для закрытия соединения предназначена функция mysql_close(идентификатор) . На самом деле, соединение будет закрыто автоматически при завершении работы сценария, поэтому специально его можно и не закрывать.

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

Функция mysql select db (имя базы данных [, иден­тификатор]) выбирает базу данных:

<?

@ $db = mysql pconnect("mtw. ru", "bogatej", "пароль");

If (!$db)

{

Echo "Подключение к базе данных прервано; повторите попытку позже.";

}

Mysql select db("db1 bogatej");

?>

Обязательно нужно обрабатывать ситуацию, когда подключение к базе данных по каким-то причинам не было установлено. Это может происходить из-за чрезмерной нагрузке на сервер (наплыв пользовате­лей, хакерские атаки) или при ошибках в сценарии. В любом случае по­сетитель (если он не один из этих хакеров) не виноват в отказе БД, и ему нужно предоставить максимально корректное сообщение о том, что ему стоит делать.

Обычно программисты пишут текст вроде «Не удалось подклю­читься к базе данных» и на этом успокаиваются. Во-первых, посети­телю незачем сообщать техническую информацию. Во-вторых, ему важнее знать, заработает ли сайт, или беда с БД надолго. Что можно в этом случае сделать? В случае отказа БД воспользоваться функцией mail() и отправить письмо разработчику или владельцу сайта: в этом случае скорее начнутся «ремонтные работы». Сообщение должно чет­ко указывать, когда посетитель может зайти снова и обнаружить рабо­тающий сайт.

Все запросы к выбранной базе данных отправляются функцией mysql_query(TeKCT запроса). Текст запроса модет содержать про­бельные символы и символы новой строки (n) и должен быть состав­лен по правилам синтаксиса SQL. Пример:

$q = mysql_query(”SELECT * FROM mytable”);

В этом случае в переменную $q запишется все содержимое таблицы mytable. (Каждая база данных может содержать множест­во таблиц.) После выполнения запроса результат нужно обработать определенным образом. Основные функции для обработки запроса таковы:

Mysql result(идентификатор запроса, номер ряда, номер столбца)

Возвращает значение одной ячейки результата запроса.

Mysql fetch array(идентификатор запроса)

Обрабатывает ряд результата запроса, возвращая массив: значе­ния в массиве с индексами по названию колонок.

Mysql fetch го^^идентификатор запроса)

Обрабатывает ряд результата запроса, возвращая неассоциатив­ный массив. Каждая колонка распологается в следующей ячейке масси­ва. Массив начинается с индекса 0.

Рассмотрим небольшой пример.

Предположим, в таблице хранится такой набор данных:

Email Name Last Name

Ivanov@mail. ru Иван Иванов

Petrov@mail. ru Петр Петров

Вывести это в браузер можно следующим образом:

<?

$rows = mysql num rows($q);

$fields = mysql num fields($q); for ($c=0; $c<$rows; $c++) {

For ($cc=0; $cc<$fields; $cc++) {

Echo mysql result($q, $c, $cc)." — "; echo "<br />";

}

}

?>

Функция mysql_num_rows() подсчитывает количество рядов (записей) в таблице, идентификатором которой является переменная $q, а функция mysql_num_fields() — количество полей. Функция mysql_result() выводит фрагменты информации, используя пере­данные ей идентификатор запроса, номер поля и номер колонки.

Выше был приведен пример запроса с оператором SELECT, кото­рый позволяет выбирать из БД данные. Естественно, им дело не огра­ничивается.

Например, с помощью оператора CREATE можно создать таблицу в БД, причем параметрами таблицы будут имя таблицы, имена полей, типы полей и модификаторы (модификатор NOT NULL обозначает, что поле не может быть пустым, PRIMARY KEY — что поле будет идентифи­катором записи), например:

CREATE TABLE CLIENTS

(

D

I

_

C

Int

NOT

NULL,

FIO

Char(40)

NOT

NULL,

ADDR

Char(30)

NOT

NULL,

CITY

Char(2 0)

NOT

NULL,

PHONE

Char(11)

NOT

NULL

);

Чаще удобнее создавать таблицы, используя специализированные системы управления базами данных (например, phpMyAdmin), а на от­куп PHP оставить «повседневные» запросы (чтение, внесение, редакти­рование и удаление данных).

Внесение данных в поля таблицы осуществляется оператором INSERT, имеющим такой синтаксис: INSERT INTO Имя_таблицы [(Список полей)] VALUES (Список значений), например: INSERT INTO CLIENTS VALUES (1, 'Иванов И. И.', 'Вокзаль­ная 3', 'Москва', '09599911100').

Редактирование (или «обновление» в терминологии MySQL) осу­ществляется с помощью оператора UPDATE, имеющего следующий син­таксис: UPDATE Имя таблицы SET Поле1 = Значение1, ... ,

ПолеN = ЗначениеN [WHERE Условие] — если не задать условие, будет модифицирована вся таблица. Пример: UPDATE CLIENTS SET CITY = 'Псков' WHERE C_ID = 1.

Наконец, удаление записей произволится оператором DELETE, например: DELETE FORM CLIENTS WHERE C_ID > 5 (что удалит все записи, где число идентификатора больше пяти). Чтобы удалить все записи из таблицы, можно написать: DELETE FROM CLIENTS.

Более подробную информацию об операторах можно найти по ад­ресу: Http://Php.Su/Mysql/7Commands. Все эти операторы включаются в ка­вычках в функцию mysql_query("тело запрос") как тело запроса.

Язык PHP позволяет также передавать данные со страницы на страницу без использования форм и даже без постоянной пересыл­ки этих данных с сервера на клиентскую машину. Наиболее удобным способом для этого являются Cookies, речь о которых идет в главе «Что модно и что можно».

Итак, в больших возможностях серверных языков мы имели воз­можности убедиться. Примеров же использования масса. Например, автоформатирование текстов на лету: включаемый текст можно сначала разметить нужным образом, а потом выдавать пользователям. Символ n заменяется на <br />, и тем самым логические абзацы превращают­ся в HTML-абзацы.

Адреса электронной почты, записанные без тэгов ссылки, легко превратить в действующие адреса, применив регулярные выражения. Допустим, файл включается не методом require (include), а сначала считывается как текстовая строка, обрабатывается, а затем выводится как значение переменной $includ_file. Перед выводом напишем та­кую строчку:

$includ file = eregi replace("([[:alnum:].- _]+@([[:alnum:]-]+.){1~,}[[:alnum:]]{2,4})","<a href='mailto:\1'>\1</a>",$includ file);

А уже затем echo $includ_file. Строчка, с помощью регуляр­ных выражений преобразующая текстовые фрагменты в действующий адрес, допускает использование в имени пользователя буквенно-циф-

Сайт выполняет черную работу

4.3

Ровых символов, точки, дефиса и знака нижнего подчеркивания. После знака «собака» может идти несколько доменных имен разного уровня, но первый уровень ограничен длиной от 2 до 4 символов (от ru, it и pl до info). Если есть вероятность, что будут писать из зон. travel, можно вместо четверки поставить шестерку.

Алгоритм, преобразующий URL-адреса в действующие ссыл­ки, длиннее, потому что настолько четко не структурирован и на него накладывается меньше ограничений. При этом алгоритм должен быть нечувствительным к адресам, которые уже оформлены как HTML-ги­перссылки. Программист Андрей Шитов реализовал этот алгоритм на языке Perl таким образом:

Sub make href{

My $text = shift;

My $ret = '';

While ($text =~ m{((?:[A<]*</ [A>]>)+(?:[A<]*)|[A<]*)(<[A>]+>)?}gm){

# $1 == текст до первого открывающего тега (включая все закрывающие теги);

# $2 == открывающий тег.

My ($subtext, $starttag) = ($1, $2);

$ret.= find links ($subtext) if $subtext;

$ret.= $starttag if $starttag;

}

$ret =~ s{(<a[A>]*>)<a[A>]*>([A<]+)</a></ a>}{$1$2</a>}gmi;

Return $ret;

}

Sub find links{

My $text = shift;

$text =~ s{((?:(?:ht|f)tps?://|www.)[A<s n]+)(?<![].,:;!})<-])}

{<a href="$1">$1</a>$2}gmsi;

$text =~ s{href="www.}{href="http:// www.}gmsi;

Return $text;

}

Работа происходит так. Основная функция make href() прини­мает исходный текст и последовательно отыскивает в нем все открыва­ющие теги. Это происходит в цикле while. После сопоставления с шаб­лоном переменная $1 получает часть строки до первого открывающего

Тега. Сам тег попадает в переменную $2. Затем подстрока, содержащаяся в первой переменной ($subtext), передается функции find_links(), где и происходит собственно поиск и выделение гиперссылок. Основ­ную работу выполняет первый оператор замены sUUgmsi. (Пример взят со страницы webcode. ru/re/href/.)

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

По ту сторону Веб-страницы

Словарь

Ботки. Обычно расширения состоят из трех букв (exe, gif, php, mov, bmp, eps, swf, asp, m3u, avi, rtf, txt, zip, cpp), но встречаются также двухбуквенные (js, ai) и четырехбуквенные (html, …

Справочник для внутреннего использования

Навигация есть признание того, что твоя страница далека от иде­ала. Ибо если бы она была близка к нему, зачем бы потребовалось покидать ее? А если ее не требуется покидать, зачем …

Алфавит от Google

Есть такая тестирующаяся поисковая подсистема от Google (Http://Www.Google.Com/Webhp?Complete=1&Hl=En), в которой по введенным первым буквам предлагаются наиболее часто за­прашиваемые слова. Я собрал все первые (наиболее рейтинговые) слова на каждую букву русского …

Как с нами связаться:

Украина:
г.Александрия
тел./факс +38 05235  77193 Бухгалтерия

+38 050 457 13 30 — Рашид - продажи новинок
e-mail: msd@msd.com.ua
Схема проезда к производственному офису:
Схема проезда к МСД

Партнеры МСД

Контакты для заказов оборудования:

Внимание! На этом сайте большинство материалов - техническая литература в помощь предпринимателю. Так же большинство производственного оборудования сегодня не актуально. Уточнить можно по почте: Эл. почта: msd@msd.com.ua

+38 050 512 1194 Александр
- телефон для консультаций и заказов спец.оборудования, дробилок, уловителей, дражираторов, гереторных насосов и инженерных решений.