Сайт выполняет черную работу
С одной стороны, чаще всего при создании сложных сайтов приходится выполнять десятки и сотни рутинных операций. Примеров масса. В каждый из файлов должен быть вставлен навигационный блок; при этом на каждой данной странице ссылка на эту страницу должна быть заменена обычным текстом. При подготовке статистических таблиц приходится каждый раз повторять одинаковые фрагменты данных. Если верстка всех страниц сайта основана на одном шаблоне, то дело, конечно, упрощается.
С другой стороны, каждый разработчик (хотя бы и в душе) считает себя творческим человеком, несовместимым с рутиной, а рутинные операции человечество издавна мечтало переложить на плечи роботов (лень — двигатель прогресса; не зря же были изобретены пылесосы). Полностью это сделать пока не удалось, но программисты и веб-разработчики по сравнению с остальной частью человечества находятся в более выгодном положении: в их распоряжении есть такая замечательная вещь, как серверные языки программирования. А в большинстве серверных языков есть массивы (которые позволяют упорядочить данные), циклы (которые повторяют одни и те же операции с разными модификациями в зависимости от условий), условные операторы (которые и устанавливают эти условия), переменные (фрагменты текста, несущие разное значение в зависимости от переданных значений или разных условий), функции (апофеоз «правила лени и прогресса»: функция — набор команд, которые должны повторяться в разных местах кода, при этом в функции можно передавать разные значения, в зависимости от чего функция может вести себя абсолютно по-разному). Кроме того, серверные языки поддерживают включение одного файла в другой: это значит, что повторяющиеся фрагменты кода (которые есть почти на каждом сайте) можно просто вынести в отдельный файл, а затем
Включать этот файл в нужном месте. Так поступают с фрагментами, содержащими навигационное меню и другие повторяющиеся фрагменты: добавление в меню одного раздела в связи с этим сводится к добавлению одной строчки в один файл, а не к редактированию каждой страницы.
Приведем пример. Допустим, на сайте есть несколько разделов, каждый из которых «обслуживает» одна ссылка в меню. Сайт состоит из непостоянного количества страниц: периодически разделы то добавляются, то удаляются. Меню представляет собой строчку, в которой ссылки разделяются обратным слэшем; после последней ссылки, понятное дело, слэша нет. Создаем файл сценария на языке 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 |
"Э"=>"е" |
"Ю"=>"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> </p><p class="success">Файл успешно загружен под именем «'.$newname.'» в директорию «'.str replace("./","",$choice of folder ).'»'.$addcommentfile.'</p><p> </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 (
|
); |
Чаще удобнее создавать таблицы, используя специализированные системы управления базами данных (например, 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/.)
Стоит упомянуть о такой деликатной вещи, как фильтр нецензурной лексики, чтобы предотвратить ее появление на тех страницах, где посетители вольны оставлять сообщения. Реализовать его очень просто: вручную создается массив, в котором записаны различные формы или корневые элементы нецензурных слов (в этом случае программисту нужно уметь выражаться едва ли не более мастерски, чем посетителям сайта), а затем с помощью цикла эти элементы заменяются на три звездочки или что-то вроде текста «[вырезано цензурой]» — на ваше усмотрение. Проводить такую замену лучше не при записи в файл или базу данных, а перед выводом на экран — любопытно же, что там написано.