Содержание
Что такое PHP?
- PHP
- (рекурсивный акроним словосочетания "PHP: Hypertext Preprocessor") - это широко используемый язык программирования общего назначения с открытым исходным кодом. PHP сконструирован специально для ведения Web-разработок и может внедряться в HTML-код.
Простой ответ, но что он может означать? Вот пример:
Пример 1-1. Пример программирования на PHP
<head>
<title>Пример </title>
</head>
<body>
<?php
echo "Привет, я - скрипт PHP!";
?>
</body>
</html>
Обратите внимание на отличие этого скрипта от скриптов, написанных на других языках, например, на Perl или C - вместо того, чтобы создавать программу, которая занимается формированием HTML-кода и содержит бесчисленное множество предназначенных для этого команд, вы создаете HTML-код с несколькими внедренными командами PHP (в приведенном случае, предназначенными для вывода текста). Код PHP отделяется специальными начальным и конечным тегами, которые позволяют процессору PHP определять начало и конец участка HTML-кода, содержащего PHP-скрипт.
Значительным отличием PHP от какого-либо кода, выполняющегося на стороне клиента, например, JavaScript, является то, что PHP-скрипты выполняются на сервере. Если бы у вас на сервере был размещен скрипт, подобный вышеприведенному, клиент получил бы только результат выполнения скрипта, причем он не смог бы выяснить, какой именно код выполняется. Вы даже можете сконфигурировать свой сервер таким образом, чтобы HTML-файлы обрабатывались процессором PHP, так что клиенты даже не смогут узнать, получают ли они обычный HTML-файл или результат выполнения скрипта.
PHP крайне прост для освоения, но вместе с тем способен удовлетворить запросы профессиональных программистов. После того, как вы впервые услышали о PHP, и открыли это руководство, в течение нескольких часов вы уже сможете создавать простые PHP-скрипты.
Хотя PHP, главным образом, предназначен для работы в среде web-серверов, область его применения не ограничивается только этим. Читайте дальше и не пропустите главу Возможности PHP.
PHP может все. Главным образом, область применения PHP сфокусирована на написание скриптов, работающих на стороне сервера; таким образом, PHP способен выполнять всё то, что выполняет любая другая программа CGI, например, обрабатывать данных форм, генерировать динамические страницы или отсылать и принимать cookies. Но PHP способен выполнять и множество других задач.
Существуют три основных области, где используется PHP.
- Создание скриптов для выполнения на стороне сервера. PHP наиболее широко используется именно таким образом. Все, что вам понадобится, это парсер PHP (в виде программы CGI или серверного модуля), вебсервер и броузер. Чтобы вы могли просматривать результаты выполнения PHP-скриптов в броузере, вам нужен работающий вебсервер и установленный PHP. За более подробными сведениями обратитесь к главе Советы по установке.
- Создание скриптов для выполнения в командной строке. Вы можете создать PHP-скрипт, способный запускаться вне зависимости от вебсервера и броузера. Все, что вам потребуется - парсер PHP. Такой способ использования PHP идеально подходит для скриптов, которые должны выполняться регулярно, например, с помощью cron (на платформах *nix или Linux) или с помощью планировщика задач (Task Scheduler) на платформах Windows. Эти скрипты также могут быть использованы в задачах простой обработки текстов. За дополнительной информацией обращайтесь к главе Использование PHP в среде командной строки.
- Создание приложений GUI, выполняющихся на стороне клиента. Возможно, PHP является не самым лучшим языком для создания подобных приложений, но, если вы очень хорошо знаете PHP и хотели бы использовать некоторые его возможности в своих клиент-приложениях, вы можете использовать PHP-GTK для создания таких приложений. Подобным образом вы можете создавать и кросс-платформенные приложения. PHP-GTK является расширением PHP и не поставляется вместе с дистрибутивом PHP. Если вы заинтересованы, посетите сайт PHP-GTK.
PHP доступен для большинства операционных систем, включая Linux, многие модификации Unix (такие, как HP-UX, Solaris и OpenBSD), Microsoft Windows, Mac OS X, RISC OS, и многих других. (Совершенно точно, что существует версия PHP для OS/2. Неизвестно, правда, насколько соответствующая нынешним реалиям - Прим.перев.) Также в PHP включена поддержка большинства современных вебсерверов, таких, как Apache, Microsoft Internet Information Server, Personal Web Server, серверов Netscape и iPlanet, сервера Oreilly Website Pro, Caudium, Xitami, OmniHTTPd и многих других. Для большинства серверов PHP поставляется в качестве модуля, для других, поддерживающих стандарт CGI, PHP может функционировать в качестве процессора CGI.
Таким образом, выбирая PHP, вы получаете свободу выбора операционной системы и вебсервера. Кроме того, у вас появляется выбор между использованием процедурного или объектно-ориентированного программирования или же их сочетания. Несмотря на то, что текущая версия PHP поддерживает не все особенности ООП, многие библиотеки кода и большие приложения (включая библиотеку PEAR) написаны только с использованием ООП.
PHP способен не только выдавать HTML. Возможности PHP включают формирование изображений, файлов PDF и даже роликов Flash (с использованием libswf и Ming), создаваемых "на лету". PHP также способен выдавать любые текстовые данные, такие, как XHTML и другие XML-файлы. PHP способен осуществлять автоматическую генерацию таких файлов и сохранять их в файловой системе вашего сервера вместо того, чтобы отдавать клиенту, организуя, таким образом, кеш динамического содержания, расположенный на стороне сервера.
Одним из значительных преимуществ PHP является поддержка широкого круга баз данных. Создание скрипта, использующего базы данных, - невероятно просто. В настоящее время 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
Также в PHP включена поддержка DBX для работы на абстрактном уровне, так что вы можете работать с любой базой данных, использующих DBX. Кроме того, PHP поддерживает ODBC (Open Database Connection standard), таким образом, вы можете работать с любой базой данных, поддерживающей этот всемирно признанный стандарт.
PHP также поддерживает "общение" с другими сервисами с использованием таких протоколов, как LDAP, IMAP, SNMP, NNTP, POP3, HTTP, COM (на платформах Windows) и многих других. Кроме того, вы получаете возможность работать с сетевыми сокетами "напрямую". PHP поддерживает стандарт обмена сложными структурами данных WDDX. Обращая внимание на взаимодействие между различными языками, следует упомянуть о поддержке объектов Java и возможности их использования в качестве объектов PHP. Для доступа к удаленным объектам вы можете использовать расширение CORBA.
PHP включает средства обработки текстовой информации, начиная с регулярных выражений Perl или POSIX Extended и заканчивая парсером документов XML. Для парсинга XML используются стандарты SAX и DOM. Для преобразования документов XML вы можете использовать расширение XSLT.
Используя PHP в области электронной коммерции, вы обратите внимание на функции осуществления платежей Cybercash, CyberMUT, VeriSign Payflow Pro и CCVS.
Последним по порядку, но не по значению, является поддержка многих других расширений, таких, как функции поисковой машины mnoGoSearch, функции IRC Gateway, функции для работы со сжатыми файлами (gzip, bz2), функции календарных вычислений, функции перевода...
Как вы видите, этой страницы не хватит для того, чтобы перечислить все, что может предложить вам PHP. Читайте следующую главу, Установка PHP и обратитесь к главе Справочник по функциям за более подробными сведениями о перечисленных выше расширениях.
Содержание
Что потребуется?
Первая страница на PHP
Делаем что-нибудь полезное
Работа с формами
Использование старых программ с новыми версиями PHP
Что дальше?
В данном кратком руководстве на примерах объясняются основы PHP. Это руководство включает в себя только создание динамических Web-страниц с помощью PHP, однако реальная область применения PHP гораздо шире. В разделе "Что может PHP" приведена дополнительная информация.
Созданные с использованием PHP Web-страницы обрабатываются, как обычные HTML-страницы. Их можно создавать и изменять точно таким же образом, как и обычные страницы на HTML.
В данном руководстве мы предполагаем, что ваш сервер имеет поддержку PHP и что все файлы, заканчивающиеся на .php, обрабатываются PHP. В большинстве серверов это расширение используется для PHP по умолчанию, но все-таки не лишним будет уточнить это у вашего администратора сервера. Если ваш сервер поддерживает PHP, то у вас есть все, что требуется. Просто создавайте ваши файлы .php и размещайте их в вашем каталоге Web-сервера - они будут обрабатываться автоматически. Не нужно ничего компилировать, не нужно никаких дополнительных программ. Считайте файлы PHP обычными файлами HTML с набором новых "волшебных" тегов, которые позволяют вам делать все, что угодно.
Создайте файл с именем hello.php в корневом каталоге ваших документов Web-сервера и запишите в него следующее:
Пример 2-1. Первый скрипт на PHP: hello.php
<head>
<title>Тестируем PHP</title>
</head>
<body>
<?php echo "Привет!<p>"; ?>
</body>
</html>
Эта программа выведет следующее:
<head>
<title>Тестируем PHP</title>
</head>
<body>
Привет!<p>
</body>
</html>
Заметим, что сходства со скриптами на CGI нет. Файл не обязан быть выполнимым или отмеченным любым другим образом. Это просто обычный файл HTML, в котором есть набор специальных тегов, делающих много интересного.
Эта программа чрезвычайно проста, и для создания настолько простой странички даже необязательно использовать PHP. Все что она делает - это выводит "Привет! с использованием функции PHP echo().
Если у вас этот пример не отображает ничего или выводит окно загрузки, или если вы видите весь этот файл в текстовом виде, то весьма вероятно, что ваш Web-сервер не имеет поддержки PHP. Попросите вашего администратора сервера включить такую поддержку. Предложите ему инструкцию по установке - раздел "Установка" данной документации. Если же вы хотите разрабатывать скрипты на PHP дома, то вам в раздел необходимые файлы. Дома можно разрабатывать скрипты с использованием любой операционной системы, но вам понадобится установить соответствующий Web-сервер.
Цель примера - показать формат специальных тегов PHP. В этом примере мы использовали <?php в качестве открывающего тега, затем шли команды PHP, завершающиеся закрывающим тегом ?>. Таким образом можно сколько угодно раз переходить к коду PHP в файле HTML.
Пара слов о текстовых редакторах: Существует множество текстовых редакторов и интегрированных сред разработки (IDE), в которых вы можете создавать и редактировать файлы PHP. Список некоторых редакторов содержится в разделе "Список редакторов PHP". Если вы хотите порекомендовать какой-либо редактор, посетите данную страницу и попросите добавить данный редактор в список.
Пара слов о текстовых процессорах: Текстовые процессоры (StarOffice Writer, Microsoft Word, Abiword и др.) в большинстве случаев не подходят для редактирования файлов PHP.
Если вы используете текстовый процессор для создания скриптов на PHP, вы должны быть уверены, что сохраняете файл, как ЧИСТО ТЕКСТОВЫЙ. В противном случае PHP не сможет обработать и выполнить вашу программу.
Пара слов о "Блокноте" Windows: При написании скриптов PHP с использованием встроенного "Блокнота" Windows необходимо сохранять файлы с расширением .php. "Блокнот" автоматически добавляет расширение .txt. Для обхода этой проблемы существует несколько методов.
Можно поместить название файла в кавычки (пример:"hello.php").
Кроме того, можно выбрать "Все файлы" вместо "Текстовые документы" из ниспадающего списка с типами файлов в окне сохранения. После этого можно вводить имя файла без кавычек.
Давайте сделаем что-нибудь полезное. К примеру, определим, какой браузер использует тот, кто смотрит в данный момент нашу страницу. Для этого мы проверим строку с именем браузера, посылаемую нам в HTTP-запросе. Эта информация хранится в переменной. Переменные в PHP всегда предваряются знаком доллара. Интересующая нас в данный момент переменная называется $_SERVER["HTTP_USER_AGENT"].
Пару слов об автоматической глобализации переменных в PHP: $_SERVER - специальная зарезервированная переменная PHP, которая содержит всю информацию, полученную от Web-сервера. Она является автоглобализованной (или суперглобальной). Для более подробной информации смотрите раздел "Суперглобальные переменные". Эти специальные переменные появились в PHP, начиная с версии 4.1.0. До этого использовались массивы $HTTP_*_VARS, такие, как $HTTP_SERVER_VARS. Эти массивы, несмотря на то, что они уже устарели, до сих пор существуют (см. замечания по старым программам).
Для вывода данной переменной мы сделаем так:
Пример 2-2. Вывод значения переменной (элемента массива)
Пример вывода данной программы:
В PHP есть огромное количество типов переменных. В предыдущем примере мы печатали элемент массива. Массивы в PHP являются очень мощным средством.
$_SERVER - просто переменная, которая предоставлена вам языком PHP. Список таких переменных можно посмотреть в разделе "Зарезервированные переменные". А можно получить их полный список с помощью такой программы:
Пример 2-3. Показываем все стандартные переменные с помощью функции phpinfo()
Если открыть данный файл в браузере, вы увидите страничку с информацией о PHP, а также список всех доступных вам переменных.
Внутрь тегов PHP можно помещать множество команд и создавать кусочки кода, делающие гораздо большее, чем просто вывод на экран. К примеру, если мы хотим сделать проверку на Internet Explorer, мы можем поступить так:
Пример 2-4. Пример использования управляющих структур и функций
if (strstr($_SERVER["HTTP_USER_AGENT"], "MSIE")) {
echo "Вы используете Internet Explorer<br />";
}
?>
Пример вывода данной программы:
Здесь мы показали несколько новых элементов. Во-первых, здесь есть команда if. Если вам знаком основной синтаксис языка C, то вы уже заметили что-то схожее. Если же вы не знаете C или подобного по синтаксису языка, то лучший вариант - взять какую-либо книжку по PHP и прочитать ее. Другой вариант - почитать раздел "Описание языка" данного руководства.
Во-вторых, здесь есть вызов функции strstr(). strstr() - встроенная в PHP функция, которая ищет одну строку в другой. В данном случае мы ищем строку "MSIE" в $_SERVER["HTTP_USER_AGENT"]. Если строка не найдена, эта функция возвращает FALSE, если найдена - TRUE. Если она вернет TRUE, то условие в if окажется истинным, и код в командных скобках ({ }) выполнится. В противном случае данный код не выполняется. Попробуйте создать аналогичные примеры с использованием команд if, else, и других функций, таких, как strtoupper() и strlen(). Также примеры содержатся во многих описаниях функций в данном руководстве.
Продемонстрируем, как можно входить в режим кода PHP и выходить из него прямо внутри кода:
Пример 2-5. Смешение режимов HTML и PHP
if (strstr($_SERVER["HTTP_USER_AGENT"], "MSIE")) {
?>
<h3>strstr вернул true</h3>
<center><b>Вы используете Internet Explorer</b></center>
<?php
} else {
?>
<h3>strstr вернул false</h3>
<center><b>Вы не используете Internet Explorer</b></center>
<?php
}
?>
Пример вывода данной программы:
<center><b>Вы используете Internet Explorer</b></center>
Вместо использования команды PHP echo для вывода, мы вышли из режима кода и послали содержимое HTML. Важный момент здесь - то, что логическая структура кода PHP при этом не теряется. Только одна HTML-часть будет послана клиенту в зависимости от результата функции strstr() (другими словами, в зависимости от того, найдена строка "MSIE" или нет).
Одно из главнейших достоинств PHP - то, как он работает с формами HTML. Здесь основным является то, что каждый элемент формы автоматически станет доступен вашим программам на PHP. Для подробной информации об использовании форм в PHP читайте раздел " Переменные из внешних источников". Вот пример формы HTML:
Пример 2-6. Простейшая форма HTML
Ваше имя: <input type="text" name="name" />
Ваш возраст: <input type="text" name="age" />
<input type="submit">
</form>
В этой форме нет ничего особенного. Это обычная форма HTML без каких-либо специальных тегов. Когда пользователь заполнит форму и нажмет кнопку отправки, будет вызвана страница action.php. В этом файле может быть что-то вроде:
Пример 2-7. Выводим данные нашей формы
Вам <?php echo $_POST["age"]; ?> лет.
Пример вывода данной программы:
Вам 30 лет.
Принцип работы данного кода прост и понятен. Переменные The $_POST["name"] и $_POST["age"] автоматически установлены для вас средствами PHP. Ранее мы использовали переменную $_SERVER, здесь же мы точно также используем суперглобальную переменную $_POST, которая содержит все POST-данные. Заметим, что метод отправки нашей формы - POST. Если бы мы использовали метод GET, то информация нашей формы была бы в суперглобальной переменной $_GET. Также можно использовать переменную $_REQUEST, если источник данных не имеет значения. Эта переменная содержит смесь данных GET, POST, COOKIE и FILE. Также советуем взглянуть на описание функции import_request_variables().
Использование старых программ с новыми версиями PHP
Сейчас PHP является популярным языком сценариев (скриптов). Становится все больше и больше распространяемых кусочков кода, которые вы можете использовать в своих скриптах. В большинстве случаев разработчики PHP старались сохранить совместимость с предыдущими версиями так, что код, написанный для более старой версии будет идеально работать и с новыми версиями языка без каких-либо изменений. Однако случается так, что изменения все-таки необходимы.
Есть два важных изменения, которые влияют на старые программы:
- Объявление массивов $HTTP_*_VARS устаревшими. Эти массивы требовали глобализации в функциях и процедурах. Новые суперглобальные массивы были введены, начиная с PHP 4.1.0. Это: $_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_REQUEST, и $_SESSION. Более старые массивы $HTTP_*_VARS, такие, как $HTTP_POST_VARS, существуют со времен PHP 3 и, вероятно, будут еще долго существовать для сохранения совместимости.
- Внешние переменные больше не глобализуются по умолчанию. Другими словами, директива register_globals в php.ini по умолчанию отключена ("off"), начиная с PHP 4.2.0. Рекомендуемый метод доступа к таким переменным - суперглобальные массивы, описанные выше. Более старые программы, книги и руководства могут считать, что данная директива включена ("on"). К примеру, переменная $id может поступать из строки URL http://www.example.com/foo.php?id=42. Когда указанная директива выключена, $id доступна лишь как $_GET['id'].
Для дополнительной информации касательно изменений, связанных с переменными, смотрите раздел "Предопределенные переменные"и ссылки этого раздела.
Что дальше?
То, что вы узнали, поможет вам понять большую часть руководства и разобраться в большинстве приведенных примеров программ. Другие примеры находятся на различных сайтах, ссылки на которые можно найти на php.net: http://www.php.net/links.php.
Содержание
Вставка в HTML
Разделение инструкций
Комментарии
Когда PHP обрабатывает файл, он просто передаёт его текст, пока не встретит один из специальных тегов, который сообщает ему о необходимости начать интерпретацию текста как кода PHP. Затем он выполняет весь найденный код до закрывающего тега, говорящего интерпретатору, что далее снова идет просто текст. Этот механизм позволяет вам внедрять PHP-код в HTML - все за пределами тегов PHP остается неизменным, тогда как внутри - интерпретируется как код.
Существует четыре набора тегов, которые могут быть использованы для обозначения PHP-кода. Из них только два (<?php. . .?> и <script language="php">. . .</script>) всегда доступны;другие могут быть включены или выключены в конфигурационном файле php.ini. Хотя короткие теги и теги в стиле ASP могут быть удобны, они не так переносимы, как длинные версии. Кроме того, если вы намереваетесь вставлять PHP-код в XML или XHTML, чтобы соответствовать XML, вам следует использовать форму <?php. . .?>.
Теги, поддерживаемые PHP:
Пример 5-1. Способы вставки в HTML
1. <?php echo("если вы хотите работать с документами XHTML или XML,
делайте так\n"); ?>
2. <?
echo ("это
простейшая инструкция обработки SGML\n"); ?>
<?= выражение ?> Это
синоним для "<? echo выражение
?>"
3. <script
language="php">
echo ("некоторые редакторы
(например, FrontPage) не
любят
инструкции обработки");
</script>
4. <% echo ("Вы можете по
выбору использовать теги в стиле ASP"); %>
<%= $variable; # Это
синоним для "<% echo . . ." %>
Первый способ, <?php. . .?>, наиболее предпочтительный, так как он позволяет использовать PHP в коде, соответствующем правилам XML, таком как XHTML.
Второй способ не всегда доступен. Короткие теги доступны только когда они включены. Это можно сделать, используя функцию short_tags() (только в PHP 3), включив установку short_open_tag в конфигурационном файле PHP, либо скомпилировав PHP с параметром --enable-short-tags для configure. Даже если оно включено по умолчанию в php.ini-dist, использование коротких тегов не рекомендуется.
Четвертый способ доступен только если теги в стиле ASP были включены, используя конфигурационную установку asp_tags.
Замечание: Поддержка тегов в стиле ASP была добавлена в версии 3.0.4.
Замечание: Следует избегать использования коротких тегов при разработке приложений или библиотек, предназначенных для распространения или размещения на PHP-серверах, не находящихся под вашим контролем, так как короткие теги могут не поддерживаться на целевом сервере. Для создания переносимого, совместимого кода, не используйте короткие теги.
Закрывающий тег блока PHP-кода включает сразу следующий за ним перевод строки, если он имеется. Кроме того, закрывающий тег автоматически подразумевает точку с запятой; вам не нужно заканчивать последнюю строку кода в блоке точкой с запятой. Закрывающий тег PHP-блока в конце файла не является обязательным.
PHP позволяет использовать такие структуры:
Пример 5-2. Профессиональная вставка
<?php
if ($expression) {
?>
<strong>Это истина.</strong>
<?php
} else {
?>
<strong>Это
ложь.</strong>
<?php
}
?>
Этот код работает так, как ожидается, потому что когда PHP встречает закрывающие теги ?>, он просто выводит все, что он находит до следующего открывающего тега. Приведенный здесь пример конечно придуманный, но для вывода больших блоков текста выход из режима интерпретации PHP обычно более эффективен, чем отправка всего текста через echo(), print() или что-либо подобное.
Инструкции разделяются также как и в C или Perl - каждое выражение заканчивается точкой с запятой.
Закрывающий тег (?>) также подразумевает конец инструкции, поэтому два следующих фрагмента кода эквиваленты:
PHP поддерживает комметарии в стиле 'C', 'C++' и оболочки Unix. Например:
echo "Это тест"; // Это однострочный комментарий в стиле c++
/* Это многострочный комментарий
еще одна строка комментария */
echo "Это еще один тест";
echo "Последний тест"; # Это комментарий в стиле оболочки Unix
?>
Однострочные комментарии идут только до конца строки или текущего блока PHP-кода, в зависимости от того, что идет перед ними.
Будьте внимательны, следите за отсутствием вложенных 'C'-комментариев, они могут появиться во время комментирования больших блоков.
Однострочные комментарии идут только до конца строки или текущего блока PHP-кода, в зависимости от того, что идет перед ними. Это означает, что HTML-код после // ?>БУДЕТ напечатан: ?> выводит из режима PHP и возвращает в режим HTML, но // не позволяет этого сделать. Если включена конфигурационная директива asp_tags, то же самое происходит и при // %>.
Содержание
Введение
Булев
Целые
Числа с плавающей точкой
Строки
Массивы
Объекты
Ресурс
NULL
Псевдо-типы, используемые в этой документации
Манипуляции с типами
PHP поддерживает восемь простых типов.
Четыре скалярных типа:
- boolean
- integer
- float (число с плавающей точкой или 'double')
- string
Два смешанных типа:
- array
- object
И, наконец, два специальных типа:
- resource
- NULL
Для удобства понимания в этом руководстве используется также несколько псевдо-типов:
- mixed
- number
- callback
Вы также можете найти несколько упоминаний типа двойной точности. Рассматривайте его как число с плавающей точкой, два имени существуют только по историческим причинам.
Как правило, программист не устанавливает тип переменной;предпочтительнее, чтобы это делал PHP во время выполнения программы в зависимости от контекста, в котором используется переменная.
Замечание: Если вы желаете проверить тип и значение определенного выражения, используйте var_dump().
Замечание: Если же вам для отладки необходимо просто удобочитаемое представление типа, используйте gettype(). Чтобы проверить на определенный тип, не используйте gettype(), применяйте для этого is_type функции. Вот несколько примеров:
$bool = TRUE; // логический
$str = "foo"; // строковый
$int = 12; // целочисленный
echo gettype($bool); // выводит "boolean"
echo gettype($str); // выводит "string"
// Если это целое, увеличить на четыре
if (is_int($int)) {
$int += 4;
}
// Если $bool - это строка, вывести ее
// (ничего не выводит)
if (is_string($bool)) {
echo "Строка: $bool";
}
?>
Если вы хотите принудительно изменить тип переменной, вы можете либо привести переменную, либо использовать функцию settype().
Обратите внимание, что переменная, в зависимости от ее типа в данный момент, в определенных ситуациях может иметь разные значения. Более подробную информацию смотрите в разделе Манипуляции с типами. Также вам, возможно, будет интересно посмотреть таблицы сравнения типов, поскольку в них приведены примеры связанных сравнений различных типов.
Булев
Это простейший тип. Он выражает истинность значения - это может быть либо TRUE, либо FALSE.
Замечание: Булев тип был введен в PHP 4.
Синтаксис
Чтобы определить булев тип, используйте ключевое слово TRUE или FALSE. Оба регистро-независимы.
Обычно вы используете некий оператор, который возвращает логическое выражение, а затем предает его управляющей конструкции.
<?php
// == это оператор,
который проверяет
// эквивалентность и возвращает булево значение
if (
$action
==
"показать_версию"
) {
echo
"Версия 1.23"
;
}
// это не обязательно...
if (
$show_separators
==
TRUE
) {
echo
"<hr>\n"
;
}
// ...потому что вы
можете просто написать
if (
$show_separators
) {
echo
"<hr>\n"
;
}
?>
Преобразование в булев тип
Для несомненного преобразования значения в булев тип используйте приведение типа (bool) или (boolean). Однако в большинстве случаев вам нет необходимости использовать приведение типа, поскольку значение будет автоматически преобразовано, если оператор, функция или управляющая конструкция требует булев аргумент.
Смотрите также Манипуляции с типами.
При преобразовании в логический тип, следующие значения рассматриваются как FALSE:
- Сам булев FALSE
- целое 0 (ноль)
- число с плавающей точкой 0.0 (ноль)
- пустая строка и строка "0"
- массив с нулевыми элементами
- объект с нулевыми переменными-членами
- специальный тип NULL (включая неустановленные переменные)
Все остальные значения рассматриваются как TRUE (включая любой ресурс).
Внимание
-1 считается TRUE, как и любое ненулевое (отрицательное или положительное) число!
<?php
echo
gettype
((bool)
""
);
//
bool(false)
echo
gettype
((bool)
1
);
//
bool(true)
echo
gettype
((bool)
-
2
);
//
bool(true)
echo
gettype
((bool)
"foo"
);
//
bool(true)
echo
gettype
((bool)
2.3e5
);
//
bool(true)
echo
gettype
((bool)
array(
12
));
// bool(true)
echo
gettype
((bool)
array());
// bool(false)
?>
Целые
Целое это число из множества Z = {..., -2, -1, 0, 1, 2, ...}.
Смотрите также: Целые произвольной длины / GMP, Числа с плавающей точкой и Произвольная точность / BCMath
Синтаксис
Целые могут быть указаны в десятичной, шестнадцатеричной или восьмеричной системе счисления, по желанию с предшествующим знаком (- или +).
Если вы используете восьмеричную систему счисления, вы должны предварить число 0 (нулем), для использования шестнадцатеричной системы нужно поставить перед числом 0x.
Массивы упорядочены. Вы можете изменять порядок элементов, используя различные функции сортировки. Для дополнительной информации смотрите раздел функции для работы с массивами. Вы можете подсчитать количество элементов в массиве, используя функцию count().
<?php
sort
(
$files
);
print_r
(
$files
);
?>
Поскольку значение массива может быть чем угодно, им также может быть другой массив. Таким образом вы можете создавать рекурсивные и многомерные массивы.
<?php
$fruits
= array (
"фрукты"
=> array (
"a"
=>
"апельсин"
,
"b"
=>
"банан"
,
"c"
=>
"яблоко"
),
"числа"
=> array (
1
,
2
,
3
,
4
,
5
,
6
),
"дырки"
=> array
(
"первая"
,
5
=>
"вторая"
,
"третья"
)
);
// Несколько
примеров доступа к значениям предыдущего массива
echo
$fruits
[
"дырки"
][
5
];
// напечатает "вторая"
echo
$fruits
[
"фрукты"
][
"a"
];
// напечатает "апельсин"
unset(
$fruits
[
"дырки"
][
0
]);
// удалит "первая"
// Создаст новый многомерный массив
$juices
[
"яблоко"
][
"зеленое"
] =
"хорошее"
;
?>
Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы копировать массив по ссылке, вам нужно использовать оператор ссылки.
<?php
$arr1
=
array(
2
,
3
);
$arr2
=
$arr1
;
$arr2
[] =
4
;
// $arr2 изменился,
//
$arr1 по прежнему array(2,3)
$arr3
= &
$arr1
;
$arr3
[] =
4
;
// теперь $arr1 и $arr3 эквивалентны
?>
Объекты
Инициализация объекта
Для инициализации объекта используется выражение new, создающее в переменной экземпляр объекта.
Полное рассмотрение производится в разделе Классы и Объекты.
Преобразование в объект
Если объект преобразуется в объект, он не изменяется. Если же в объект преобразуется значение любого иного типа, создается новый экземпляр встроенного класса stdClass. Если значение было пустым, новый экземпляр также будет пустым. При любом другом значении оно будет содержатся в переменной-члене scalar.
Ресурс
Ресурс - это специальная переменная, содержащая ссылку на внешний ресурс. Ресурсы создаются и используются специальными функциями. Полный перечень этих функций и соответствующих типов ресурсов смотрите в приложении.
Замечание: Тип ресурс был введен в PHP 4
Преобразование в ресурс
Поскольку тип ресурс содержит специальные указатели на открытые файлы, соединения с базой данных, область изображения и тому подобное, вы не можете преобразовать какое-либо значение в ресурс.
Освобождение ресурсов
В связи с системой подсчета ссылок, введенной в движке Zend PHP 4 автоматически определяется, что ресурс больше никуда не ссылается (как в Java). Когда это происходит, все ресурсы, которые использовались для данного ресурса, освобождаются сборщиком мусора. По этой причине маловероятно, что когда-либо будет необходимо освобождать память вручную, используя какую-нибудь free_result функцию.
Замечание: Постоянные ссылки базы данных являются особыми, они не уничтожаются сборщиком мусора. Смотрите также раздел о постоянных соединениях.
NULL
Специальное значение NULL говорит о том, что эта переменная не имеет значения. NULL - это единственно возможное значение типа NULL.
Замечание: Пустой тип был введен в PHP 4
Переменная считается NULL если
- ей была присвоена константа NULL.
- ей еще не было присвоено какое-либо значение.
- она была удалена с помощью unset().
Синтаксис
Существует только одно значение типа NULL - регистро-независимое ключевое слово NULL.
Смотрите также is_null() и unset().
Псевдо-типы, используемые в этой документации
mixed
mixed говорит о том, что параметр может принимать множество (но не обязательно все) типов.
gettype(), например, принимает все типы PHP, тогда как str_replace() принимает строки и массивы.
number
number говорит о том, что параметр может быть либо integer, либо float.
callback
Некоторые функции, такие как call_user_func() или usort() принимают в качестве параметра определенные пользователем callback-функции. Callback-функции могут быть не только простыми функциями, но также методами объектов, включая статические методы классов.
PHP-функция передается просто как строка ее имени. Вы можете передать любую встроенную или определенную пользователем функцию за исключением array(), echo(), empty(), eval(), exit(), isset(), list(), print() и unset().
Метод созданного объекта передается как массив, содержащий объект в элементе с индексом 0 и имя метода в элементе с индексом 1.
Методы статических классов также могут быть переданы без создания экземпляра объекта передачей имени класса вместо имени объекта в элементе с индексом 0.
<?php
// простой
пример callback
function
my_callback_function
() {
echo
'hello world!'
;
}
call_user_func
(
'my_callback_function'
);
// примеры
callback-метода
class
MyClass
{
function
myCallbackMethod
() {
echo
'Hello World!'
;
}
}
// вызов метода
статического класса без создания объекта
call_user_func
(array(
'MyClass'
,
'myCallbackMethod'
));
// вызов метода
объекта
$obj
= new
MyClass
();
call_user_func
(array(&
$obj
,
'myCallbackMethod'
));
?>
Манипуляции с типами
PHP не требует (и не поддерживает) явного определения типа при объявлении переменной; тип переменной определяется по контексту, в котором она используется. То есть, если вы присвоите строковое значение переменной $var, $var станет строкой. Если вы затем присвоите $var целочисленное значение, она станет целым числом.
Примером автоматического преобразования типа является оператор сложения '+'. Если любой из операндов является числом с плавающей точкой, то все операнды интерпретируются как числа с плавающей точкой, результатом будет также число с плавающей точкой. В противном случае операнды будут интерпретироваться как целые числа и результат также будет целочисленным. Обратите внимание, что это НЕ меняет типы самих операндов; меняется только то, как они вычисляются.
<?php
$foo
=
"0"
;
// $foo это строка (ASCII 48)
$foo
+=
2
;
// $foo теперь целое число (2)
$foo
=
$foo
+
1.3
;
// $foo теперь число с плавающей
точкой (3.3)
$foo
=
5
+
"10 Little Piggies"
;
// $foo это целое число (15)
$foo
=
5
+
"10 Small Pigs"
;
// $foo это целое число (15)
?>
Если последние два примера вам непонятны, смотрите Преобразование строк в числа.
Если вы хотите, чтобы переменная принудительно вычислялась как определенный тип, смотрите раздел приведение типов. Если вы хотите изменить тип переменной, смотрите settype().
Если вы хотите протестировать любой из примеров, приведенных в данном разделе, вы можете использовать функцию var_dump().
Замечание: Поведение автоматического преобразования в массив в настоящий момент не определено.
Поскольку PHP (по историческим причинам) поддерживает индексирование в строках с использованием такого же синтаксиса, как и при индексировании массива, вышеприведенный пример приводит к проблеме: следует ли $a стать массивом, первым элементом которого будет "f" или "f" должна стать первым символом строки $a?
Текущая версия PHP воспринимает второе присваивание как определение смещения строки, поэтому $a станет "f", результат же этого автоматического преобразования следует, однако, рассматривать как неопределенный. В PHP 4 для доступа к символам строки был введен новый синтаксис фигурных скобок, используйте этот синтаксис вместо вышеприведенного:
Для дополнительной информации смотрите раздел Доступ к символу в строке.
Приведение типов
Приведение типов в PHP работает так же, как и в C: имя требуемого типа записывается в круглых скобках перед приводимой переменной.
Допускаются следующие приведения типов:
- (int), (integer) - приведение к целому числу
- (bool), (boolean) - приведение к булеву типу
- (float), (double), (real) - приведение к числу с плавающей точкой (float)
- (string) - приведение к строке
- (array) - приведение к массиву
- (object) - приведение к объекту
Обратите внимание, что внутри скобок допускаются пробелы и символы табуляции, поэтому следующее равносильно по своему действию:
Замечание: Вместо приведения переменной к строке, вы можете заключить ее в двойные кавычки.
<?php
$foo
=
10
;
// $foo это целое число
$str
=
"$foo"
;
// $str это строка
$fst
= (string)
$foo
;
// $fst это также строка
// Это напечатает "они одинаковы"
if (
$fst
===
$str
) {
echo
"они одинаковы";
}
?>
Возможно, вам не совсем ясно, что происходит при приведении между типами. Для дополнительной информации смотрите разделы:
- Преобразование в булев тип
- Преобразование в целое число
- Преобразование в число с плавающей точкой
- Преобразование в строку
- Преобразование в массив
- Преобразование в объект
- Преобразование в ресурс
- Таблицы сравнения типов
Содержание
Основы
Предопределенные переменные
Область видимости переменной
Переменные переменные
Переменные вне PHP
Переменные в PHP представлены знаком доллара с последующим именем переменной. Имя переменной чувствительно к регистру.
Имена переменных соответствуют тем же правилам, что и остальные наименования в PHP. Правильное имя переменной должно начинаться с буквы или символа подчеркивания с последующими в любом количестве буквами, цифрами или символами подчеркивания Это можно отобразить регулярным выражением: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
Замечание: Для наших целей буквы здесь - это a-z, A-Z, и ASCII-символы со 127 по 255 (0x7f-0xff).
$var = "Bob";
$Var = "Joe";
echo "$var, $Var"; // выведет "Bob, Joe"
$4site = 'not yet'; // неверно; начинается с цифры
$_4site = 'not yet'; // верно; начинается с символа подчеркивания
$tдyte = 'mansikka'; // верно; 'д' это (Дополнительный) ASCII 228.
?>
В PHP 3 переменные всегда присваивались по значению. То есть, когда вы присваиваете выражение переменной, все значение оригинального выражения копируется в эту переменную. Это означает, к примеру, что после присвоения одной переменной значения другой, изменение одной из них не влияет на значение другой. Дополнительную информацию об этом способе присвоения смотрите в разделе Выражения.
PHP 4 предлагает иной способ присвоения значений переменным: присвоение по ссылке. Это означает, что новая переменная просто ссылается (иначе говоря, "становится псевдонимом" или "указывает") на оригинальную переменную. Изменения в одной переменной отражаются на оригинале, и наоборот. Это также означает, что копирования не происходит; таким образом, присвоение осуществляется быстрее. Однако, любое увеличение скорости будет хорошо заметно только в сжатых циклах или при присвоении больших массивов или объектов.
Для присвоения по ссылке, просто добавьте амперсанд (&) к началу имени присваиваемой (исходной) переменной. Например, следующий фрагмент кода дважды выводит 'My name is Bob':
$foo = 'Bob'; // Присваивает $foo значение 'Bob'
$bar = &$foo; // Ссылка на $foo через $bar.
$bar = "My name is $bar"; // Изменение $bar...
echo $bar;
echo $foo; // меняет и $foo.
?>
Важно отметить, что по ссылке могут быть присвоены только именованные переменные.
$foo = 25;
$bar = &$foo; // Это верное присвоение.
$bar = &(24 * 7); // Неверно; ссылка на неименованное выражение.
function test()
{
return 25;
}
$bar = &test(); // Неверно.
?>
Любому запускаемому скрипту PHP предоставляет большое количество предопределенных переменных. Однако, многие из этих переменных не могут быть полностью задокументированы, поскольку они зависят от запущенного сервера, его версии и настроек, а также других факторов. Некоторые из этих переменных не доступны, когда PHP запущен из командной строки. Перечень этих переменных смотрите в разделе Зарезервированные предопределенные переменные.
Внимание
Начиная с PHP 4.2.0, значение директивы register_globals по умолчанию установлено в off (отключено). Это большое изменение в PHP. Положение register_globals в off делает предопределенные переменные доступными в глобальной области видимости. Например, чтобы получить DOCUMENT_ROOT, вам необходимо будет использовать $_SERVER['DOCUMENT_ROOT'] вместо $DOCUMENT_ROOT, или $_GET['id'] из URL http://www.example.com/test.php?id=3 вместо $id, или $_ENV['HOME'] вместо $HOME.
Дополнительную информацию, связанную с этим изменением, вы можете получить, прочитав описание register_globals в разделе о настройках, главу о безопасности Использование Register Globals , а также сообщения о выпусках PHP 4.1.0 и 4.2.0.
Использование доступных зарезервированных предопределенных переменных PHP, таких как суперглобальные массивы, является предпочтительным.
Начиная с версии 4.1.0, PHP предоставляет дополнительный набор предопределенных массивов, содержащих переменные web-сервера (если они доступны), окружения и пользовательского ввода. Эти новые массивы являются особыми, поскольку они автоматически глобальны--то есть, автоматически доступны в любой области видимости. По этой причине они также известны как 'автоглобальные' или 'суперглобальные' переменные. (В PHP нет механизма определяемых пользователем суперглобальных переменных.) Суперглобальные переменные перечислены ниже; однако, перечисление их содержимого и дальнейшее обсуждение предопределенных переменных PHP и их сути смотрите в разделе Зарезервированные предопределенные переменные. Также вы заметите, что старые предопределенные переменные ($HTTP_*_VARS) все еще существуют. Начиная с PHP 5.0.0, длинные предопределенные переменные массивов PHP могут быть отключены директивой register_long_arrays.
Переменные переменных: Суперглобальные переменные не могут быть переменными переменных.
Если некоторые из переменных в variables_order не установлены, соответствующие им предопределенные массивы также останутся пустыми.
Суперглобальные переменные PHP
$GLOBALS
Содержит ссылку на каждую переменную, доступную в данный момент в глобальной области видимости скрипта. Ключами этого массива являются имена глобальны переменных. $GLOBALS существует, начиная с PHP 3.
$_SERVER
Переменные, установленные web-сервером либо напрямую связанные с окружением выполнения текущего скрипта. Аналог старого массива $HTTP_SERVER_VARS (который по-прежнему доступен, но не рекомендуется).
$_GET
Переменные, передаваемые скрипту через HTTP GET. Аналог старого массива $HTTP_GET_VARS (который по-прежнему доступен, но не рекомендуется).
$_POST
Переменные, передаваемые скрипту через HTTP POST. Аналог старого массива $HTTP_POST_VARS (который по-прежнему доступен, но не рекомендуется).
$_COOKIE
Переменные, передаваемые скрипту через HTTP cookies. Аналог старого массива $HTTP_COOKIE_VARS (который по-прежнему доступен, но не рекомендуется).
$_FILES
Переменные, передаваемые скрипту через HTTP post-загрузку файлов. Аналог старого массива $HTTP_POST_FILES (который по-прежнему доступен, но не рекомендуется). Для дополнительной информации смотрите Загрузка методом POST.
$_ENV
Переменные, передаваемые скрипту через окружение. Аналог старого массива $HTTP_ENV_VARS (который по-прежнему доступен, но не рекомендуется).
$_REQUEST
Переменные, передаваемые скрипту через механизмы ввода GET, POST и COOKIE, и которым, следовательно, нельзя доверять. Наличие и порядок включения переменных в этот массив определяется в соответствии с директивой конфигурации PHP variables_order. Этот массив не имеет прямых аналогов в версиях PHP до 4.1.0. Смотрите также import_request_variables().
Предостережение
Начиная с PHP 4.3.0, информация о файле из $_FILES больше не существует в $_REQUEST.
Замечание: При запуске из командной строки , этот массив не будет содержать записей argv и argc; они находятся в массиве $_SERVER.
$_SESSION
Переменные, зарегистрированные на данный момент в сессии скрипта. Аналог старого массива $HTTP_SESSION_VARS (который по-прежнему доступен, но не рекомендуется). Дополнительную информацию смотрите в разделе Функции обработки сессии.
Область видимости переменной
Область видимости переменной - это среда, в которой она определена. В большинстве случаев все переменные PHP имеют единую область видимости. Эта единая область видимости охватывает также включаемые (include) и требуемые (require) файлы. Например:
Здесь переменная $a будет доступна внутри включенного скрипта b.inc. Однако, внутри определенных пользователем функций вводится локальная область видимости функции. Любая, используемая внутри функции переменная, по умолчанию ограничена локальной областью видимости функции. Например:
<?php
$a
=
1
;
/* глобальная область видимости */
function
Test
()
{
echo
$a
;
/* ссылка на переменную локальной
области видимости */
}
Test
();
?>
Этот скрипт не сгенерирует никакого вывода, поскольку выражение echo указывает на локальную версию переменной $a, а в пределах этой области видимости ей не не было присвоено значение. Возможно вы заметили, что это немного отличается от языка C в том, что глобальные переменные в C автоматически доступны функциям, если только они не были перезаписаны локальным определением. Это может вызвать некоторые проблемы, поскольку люди могут нечаянно изменить глобальную переменную. В PHP, если глобальная переменная будет использоваться внутри функции, она должна быть объявлена глобальной внутри нее.
Ключевое слово global
Сначала пример использования global:
<?php
$a
=
1
;
$b
=
2
;
function
Sum
()
{
global
$a
,
$b
;
$b
=
$a
+
$b
;
}
Sum
();
echo
$b
;
?>
Вышеприведенный скрипт выведет "3". После определения $a и $b внутри функции как global все ссылки на любую из этих переменных будут указывать на их глобальную версию. Не существует никаких ограничений на количество глобальных переменных, которые могут обрабатываться функцией.
Второй способ доступа к переменным глобальной области видимости - использование специального, определяемого PHP массива $GLOBALS. Предыдущий пример может быть переписан так:
<?php
$a
=
1
;
$b
=
2
;
function
Sum
()
{
$GLOBALS
[
"b"
]
=
$GLOBALS
[
"a"
]
+
$GLOBALS
[
"b"
];
}
Sum
();
echo
$b
;
?>
$GLOBALS - это ассоциативный массив, ключом которого является имя, а значением - содержимое глобальной переменной. Обратите внимание, что $GLOBALS существует в любой области видимости, это объясняется тем, что этот массив является суперглобальным. Ниже приведен пример, демонстрирующий возможности суперглобальных переменных:
<?php
function
test_global
()
{
// Большинство предопределенных переменных не
являются
// "супер" и чтобы быть доступными
в локальной области
// видимости функции требуют указания
'global'.
global
$HTTP_POST_VARS
;
echo
$HTTP_POST_VARS
[
'name'
];
// Суперглобальные переменные доступны в любой
области
// видимости и не требуют указания 'global'.
// Суперглобальные переменные
доступны, начиная с PHP 4.1.0
echo $_POST['name'];
}
?>
Использование статических переменных
Другой важной возможностью области видимости переменной является статическая переменная. Статическая переменная существует только в локальной области видимости функции, но не теряет своего значения, когда выполнение программы выходит из этой области видимости. Рассмотрим следующий пример:
<?php
function
Test
()
{
$a
=
0
;
echo
$a
;
$a
++;
}
?>
Эта функция абсолютно бесполезна поскольку при каждом вызове она устанавливает $a в 0 и выводит "0". Инкремент переменной $a++ здесь не играет роли, так как при выходе из функции переменная $a исчезает. Чтобы написать полезную считающую функцию, которая не будет терять текущего значения счетчика, переменная $a объявляется как static:
<?php
function
Test
()
{
static
$a
=
0
;
echo
$a
;
$a
++;
}
?>
Теперь при каждом вызове функция Test() будет выводить значение $a и инкрементировать его.
Статические переменные также дают возможность работать с рекурсивными функциями. Рекурсивной является функция, вызывающая саму себя. При написании рекурсивной функции нужно быть внимательным, поскольку есть вероятность сделать рекурсию бесконечной. Вы должны убедиться, что существует адекватный способ завершения рекурсии. Следующая простая функция рекурсивно считает до 10, используя для определения момента остановки статическую переменную $count:
<?php
function
Test
()
{
static
$count
=
0
;
$count
++;
echo
$count
;
if (
$count
<
10
) {
Test
();
}
$count
--;
}
?>
Замечание: Статические переменные могут быть объявлены так, как показано в предыдущем примере. Попытка присвоить этим переменным значения, являющиеся результатом выражений, вызовет ошибку обработки.
<?php
function
foo
(){
static
$int
=
0
;
// верно
static
$int
=
1
+
2
;
// неверно (поскольку
это выражение)
static
$int
=
sqrt
(
121
);
// неверно (поскольку это тоже выражение)
$int
++;
echo
$int
;
}
?>
Ссылки с глобальными и статическими переменными
Движок Zend 1, лежащий в основе PHP 4, оперирует модификаторами переменных static и global как ссылками. Например, реальная глобальная переменная, внедренная в область видимости функции указанием ключевого слова global, в действительности создает ссылку на глобальную переменную. Это может привести к неожиданному поведению, как это показано в следующем примере:
<?php
function
test_global_ref
()
{
global
$obj
;
$obj
=
&new
stdclass
;
}
function
test_global_noref
()
{
global
$obj
;
$obj
=
new
stdclass
;
}
test_global_ref
();
var_dump
(
$obj
);
test_global_noref
();
var_dump
(
$obj
);
?>
Выполнение этого примера сгенерирует следующий вывод:
NULL
object(stdClass)(0) {
}
Аналогично ведет себя и выражение static. Ссылки не хранятся статично:
<?php
function &
get_instance_ref
()
{
static
$obj
;
echo
"Static
object: "
;
var_dump
(
$obj
);
if (!isset(
$obj
))
{
//
Присвоить
ссылку
статической
переменной
$obj
= &new
stdclass
;
}
$obj
->
property
++;
return
$obj
;
}
function &
get_instance_noref
()
{
static
$obj
;
echo
"Static
object: "
;
var_dump
(
$obj
);
if (!isset(
$obj
))
{
//
Присвоить
объект
статической
переменной
$obj
= new
stdclass
;
}
$obj
->
property
++;
return
$obj
;
}
$obj1
=
get_instance_ref
();
$still_obj1
=
get_instance_ref
();
echo
"\n"
;
$obj2
=
get_instance_noref
();
$still_obj2
=
get_instance_noref
();
?>
Выполнение этого примера сгенерирует следующий вывод:
Static object: NULL
Static object: NULL
Static object: NULL
Static object: object(stdClass)(1) {
["property"]=>
int(1)
}
Этот пример демонстрирует, что при присвоении ссылки статической переменной она не запоминается, когда вы вызываете функцию &get_instance_ref() во второй раз.
Иногда бывает удобно иметь переменными имена переменных. То есть, имя переменной, которое может быть определено и изменено динамически. Обычная переменная определяется примерно таким выражением:
Переменная переменная берет значение переменной и рассматривает его как имя переменной. В вышеприведенном примере hello может быть использовано как имя переменной при помощи двух знаков доллара. То есть:
Теперь в дереве символов PHP определены и содержатся две переменные: $a, содержащая "hello", и $hello, содержащая "world". Таким образом, выражение
выведет то же, что и
то есть, они оба выведут: hello world.
Для того чтобы использовать переменные переменные с массивами, вы должны решить проблему двусмысленности. То есть, если вы напишете $$a[1], обработчику необходимо знать, хотите ли вы использовать $a[1] в качестве переменной, либо вам нужна как переменная $$a, а затем ее индекс [1]. Синтаксис для разрешения этой двусмысленности таков: ${$a[1]} для первого случая и ${$a}[1] для второго.
Внимание
Пожалуйста, обратите внимание, что переменные переменные не могут использоваться с Суперглобальными массивами PHP. Это означает, что вы не можете делать что-то вроде ${$_GET}. Если вы ищете способ использовать суперглобальные переменные и старые HTTP_*_VARS, вы можете попробовать ссылаться на них.
Переменные вне PHP
HTML-формы (GET и POST)
Когда происходит отправка данных формы PHP-скрипту, информация из этой формы автоматически становится доступной ему. Существует много способов получения этой информации, например:
Пример 7-8. Простая HTML-форма
<form action="foo.php" method="post">
Имя: <input type="text" name="username" /><br />
Email: <input type="text" name="email" /><br />
<input type="submit" name="submit" value="Отправь меня!" />
</form>
В зависимости от вашей индивидуальной установки и личных настроек существует много способов доступа к данным из ваших HTML-форм. Вот несколько примеров:
Пример 7-9. Доступ к данным из простой HTML POST-формы
<?php
// Доступно, начиная с PHP 4.1.0
echo $_POST['username'];
echo $_REQUEST['username'];
import_request_variables('p', 'p_');
echo $p_username;
// Доступно, начиная с PHP 3. Начиная с PHP 5.0.0, эти длинные предопределенные
// переменные могут быть отключены директивой register_long_arrays.
echo $HTTP_POST_VARS['username'];
// Доступно, если директива PHP register_globals = on. Начиная
// с PHP 4.2.0, значение по умолчанию register_globals = off.
// Использование/доверие этому методу непредпочтительно.
echo $username;
?>
GET-форма используется аналогично, за исключением того, что вместо POST вам нужно будет использовать соответствующую предопределенную переменную GET. GET относится также к QUERY_STRING (информация в URL после '?'). Так, например, http://www.example.com/test.php?id=3 содержит GET-данные, доступные как $_GET['id']. Смотрите также $_REQUEST и import_request_variables().
Замечание: Суперглобальные массивы, такие как $_POST и $_GET, стали доступны в PHP 4.1.0
Как уже говорилось, до PHP 4.2.0 значением register_globals по умолчанию было on (включено). А в PHP 3 оно всегда было включено. Сообщество PHP рекомендует всем не полагаться на эту директиву, поскольку предпочтительно присвоить ей значение off и писать программы исходя из этого.
Замечание: Конфигурационная директива magic_quotes_gpc влияет на значения Get, Post и Cookie. Если она включена, значение (It's "PHP!") автоматически станет (It\'s \"PHP!\"). Мнемонизация необходима при добавлении в базу данных. Смотрите также addslashes(), stripslashes() и magic_quotes_sybase.
PHP также понимает массивы в контексте переменных формы. К примеру, вы можете сгруппировать связанные переменные вместе или использовать эту возможность для получения значений списка множественного выбора select. Например, давайте отправим форму самой себе, а после отправки отобразим данные:
Пример 7-10. Более сложные переменные формы
<?php
if (isset(
$_POST
[
'action'
])
&&
$_POST
[
'action'
]
==
'submitted'
)
{
echo
'<pre>'
;
print_r
(
$_POST
);
echo
'<a
href="'
.
$_SERVER
[
'PHP_SELF'
]
.
'">
Попробуйте
еще
раз
</a>'
;
echo
'</pre>'
;
} else {
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Имя
: <input type="text" name="personal[name]" /><br />
Email: <input type="text" name="personal[email]" /><br />
Пиво
: <br />
<select multiple
name="beer[]">
<option
value="warthog">Warthog</option>
<option
value="guinness">Guinness</option>
<option
value="stuttgarter">Stuttgarter Schwabenbr
д
u</option>
</select><br />
<input type="hidden" name="action" value="submitted" />
<input type="submit" name="submit" value="
Отправь
меня
!" />
</form>
<?php
}
?>
В PHP 3 использование массивов в переменных формы ограничено одномерными массивами. В PHP 4 таких ограничений нет.
Имена переменных кнопки-изображения
При отправке формы вместо стандартной кнопки можно использовать изображение с помощью тега такого вида:
Когда пользователь щелкнет где-нибудь на изображении, соответствующая форма будет передана на сервер с двумя дополнительными переменными - sub_x и sub_y. Они содержат координаты нажатия пользователя на изображение. Опытные программисты могут заметить, что на самом деле имена переменных, отправленных браузером, содержат точку, а не подчеркивание, но PHP автоматически конвертирует точку в подчеркивание.
HTTP Cookies
PHP явно поддерживает HTTP cookies как определено в спецификации Netscape. Cookies - это механизм для хранения данных в удаленном браузере и отслеживания и идентификации таким образом вернувшихся пользователей. Вы можете установить cookies, используя функцию setcookie(). Cookies являются частью HTTP-заголовка, поэтому функция SetCookie должна вызываться до того, как браузеру будет отправлен какой бы то ни было вывод. Это ограничение аналогично ограничению функции header(). Данные, хранящиеся в cookie, доступны в соответствующих массивах данных cookie, таких как $_COOKIE, $HTTP_COOKIE_VARS, а также в $_REQUEST. Подробности и примеры смотрите на странице setcookie() руководства.
Если вы хотите присвоить множество значений одной переменной cookie, вы можете присвоить их как массив. Например:
<?php
setcookie
(
"MyCookie[foo]"
,
"
Тест
1"
,
time
()+
3600
);
setcookie
(
"MyCookie[bar]"
,
"
Тест
2"
,
time
()+
3600
);
?>
Это создаст две разные cookie, хотя в вашем скрипте MyCookie будет теперь одним массивом. Если вы хотите установить именно одну cookie со множеством значений, примите во внимание сначала применение к значениям таких функций, как serialize() или explode().
Обратите внимание, что cookie заменит предыдущую cookie с тем же именем в вашем браузере, если только путь или домен не отличаются. Так, для приложения корзины покупок вы, возможно, захотите сохранить счетчик. То есть:
Пример 7-11. A setcookie() example
<?php
if (isset(
$_COOKIE
[
'count'
]))
{
$count
=
$_COOKIE
[
'count'
]
+
1
;
} else {
$count
=
1
;
}
setcookie
(
"count"
,
$count
,
time
()+
3600
);
setcookie
(
"Cart[$count]"
,
$item
,
time
()+
3600
);
?>
Точки в именах приходящих переменных
Как правило, PHP не меняет передаваемых скрипту имен переменных. Однако следует отметить, что точка не является корректным символом в имени переменной PHP. Поэтому рассмотрим такую запись:
<?php
$varname
.
ext
;
/* неверное имя переменной */
?>
В данном случае интерпретатор видит переменную $varname, после которой идет оператор конкатенации, а затем голая строка (то есть, не заключенная в кавычки строка, не соответствующая ни одному из ключевых или зарезервированных слов) 'ext'. Очевидно, что это не даст ожидаемого результата.
По этой причине важно заметить, что PHP будет автоматически заменять любые точки в именах приходящих переменных на символы подчеркивания.
Определение типов переменных
Поскольку PHP определяет и конвертирует типы переменных (в большинстве случаев) как надо, не всегда очевидно, какой тип имеет данная переменная в конкретный момент времени. PHP содержит несколько функций, позволяющих определить тип переменной, таких как: gettype(), is_array(), is_float(), is_int(), is_object() и is_string(). Смотрите также раздел Типы.
Содержание
Синтаксис
Предопределенные константы
Константы - это идентификаторы простых значений. Исходя из их названия, нетрудно понять, что их значение не может изменяться в ходе выполнения скрипта (исключения представляют "волшебные" константы, которые на самом деле не являются константами в полном смысле этого слова). Имена констант чувствительны к регистру. По принятому соглашению, имена констант всегда пишутся в верхнем регистре.
Имя константы должно соответствовать тем же правилам, которыми руководствуются и другие имена в PHP. Правильное имя начинается с буквы или символа подчеркивания и состоит из букв, цифр и подчеркиваний. Регулярное выражение для проверки правильности имени константы выглядит так: [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
Замечание: Понятие "буквы" здесь - это символы a-z, A-Z, и другие символы с ASCII-кодами от 127 до 255 (0x7f-0xff).
Как и суперглобальные переменные, константы доступны из любой области видимости. Вы можете использовать константы в любом месте вашего скрипта, не обращая внимания на текущую область видимости. Подробную информацию об областях видимости можно найти здесь.
Вы можете определить константу с помощью функции define(). После того, как константа определена, ее значение не может быть изменено или аннулировано.
Константы могут содержать только скалярные данные (логического, целого, плавающего и строкового типов).
Получить значение константы можно, указав ее имя. В отличие от переменных, вам не потребуется предварять имя константы символом $. Также вы можете использовать функцию constant() для получения значения константы, если вы формируете имя константы динамически. Используйте функцию get_defined_constants() для получения списка всех объявленных констант.
Замечание: Константы и (глобальные) переменные находятся в разном пространстве имен. Это означает, что, например, TRUE и $TRUE являются совершенно разными вещами.
Если вы используете неопределенную константу, PHP предполагает, что вы имеете ввиду само имя константы, как если бы вы указали переменную типа строка (CONSTANT и "CONSTANT"). При этом будет сгенерирована ошибка типа E_NOTICE. Смотрите также главу руководства, которая разъясняет, почему $foo[bar] - это неправильно (конечно, если вы перед этим не объявили bar как константу с помощью define()). Если вы просто хотите проверить, определена ли константа, используйте функцию defined().
Различия между константами и переменными:
- У констант нет приставки в виде знака доллара ($);
- Константы можно определить только с помощью функции define(), а не присваиванием значения;
- Константы могут быть определены и доступны в любом месте без учета области видимости;
- Константы не могут быть определены или аннулированы после первоначального объявления; и
- Константы могут иметь только скалярные значения.
Пример 8-1. Определение констант
define("CONSTANT", "Здравствуй, мир.");
echo CONSTANT; // выводит "Здравствуй, мир."
echo Constant; // выводит "Constant" и выводит предупреждениее.
?>
PHP предоставляет большой список предопределенных констант для каждого выполняемого скрипта. Многие из этих констант определяются различными модулями и будут присутствовать только в том случае, если эти модули доступны в результате динамической загрузки или в результате статической сборки.
Есть пять волшебных констант, которые меняют свое значение в зависимости от контекста, в котором они используются. Например, значение __LINE__ зависит от строки в скрипте, на которой эта константа указана. Специальные константы нечувствительны к регистру и их список приведен ниже:
Таблица 8-1. Некоторые "волшебные" константы PHP
Имя |
Описание |
__LINE__ |
Текущая строка в файле. |
__FILE__ |
Полный путь и имя текущего файла. |
__FUNCTION__ |
Имя функции. (Добавлена в PHP 4.3.0.) |
__CLASS__ |
Имя класса. (Добавлена в PHP 4.3.0.) |
__METHOD__ |
Имя метода класса. (Добавлена в PHP 5.0.0) С полным списком предопределенных констант можно ознакомиться в соответствующем разделе. Выражения - это краеугольный камень PHP. Почти все, что вы пишите в PHP, является выражением. Самое простое и точное определение выражения - "все что угодно, имеющее значение". Основными формами выражений являются константы и переменные. Если вы записываете "$a = 5", вы присваиваете '5' переменной $a. '5', очевидно, имеет значение 5 или, другими словами, '5' это выражение со значением 5 (в данном случае '5' это целочисленная константа). После этого присвоения вы ожидаете, что значением $a также является 5, поэтому, если вы написали $b = $a, вы полагаете, что работать это будет так же, как если бы вы написали $b = 5. Другими словами, $a это также выражение со значением 5. Если все работает верно, то именно так и произойдет. Немного более сложными примерами выражений являются функции. Например, рассмотрим следующую функцию: Исходя из того, что вы хорошо знакомы с концепцией функций (если нет, то прочитайте главу о функциях), вы полагаете, что запись $c = foo() абсолютно эквивалента записи $c = 5, и вы правы. Функции - это выражения, значением которых является то, что возвращает функция. Поскольку foo() возвращает 5, значением выражения 'foo()' является 5. Как правило, функции возвращают не просто статическое значение, а что-то вычисляют. Разумеется, значения в PHP не обязаны быть целочисленными, и очень часто ими не являются. PHP поддерживает три типа скалярных значений: целочисленные, с плавающей точкой и строковые значения (скалярными являются значения, которые вы не можете 'разбить' на меньшие части, в отличие, например, от массивов). PHP поддерживает также два комбинированных (не скалярных) типа: массивы и объекты. Каждый из этих типов значений может присваиваться переменной или возвращаться функцией. До сих пор пользователи PHP/FI 2 не должны были почувствовать каких-либо изменений. Однако PHP, как и многие другие языки, понимает гораздо больше выражений. PHP - это язык, ориентированный на выражения и рассматривающий почти все как выражение. Вернемся к примеру, с которым мы уже имели дело: '$a = 5'. Легко заметить, что здесь присутствуют два значения - значение целочисленной константы '5' и значение переменной $a, также принимающей значение 5. Но на самом деле здесь присутствует и еще одно значение - значение самого присвоения. Само присвоение вычисляется в присвоенное значение, в данном случае - в 5. На практике это означает, что '$a = 5', независимо от того, что оно делает, является выражением со значением 5. Таким образом, запись '$b = ($a = 5)' равносильна записи '$a = 5; $b = 5;' (точка с запятой обозначает конец выражения). Поскольку операции присвоения анализируются справа налево, вы также можете написать '$b = $a = 5'. Другой хороший пример ориентированности на выражения - пре- и постфиксный инкремент и декремент. Пользователи PHP/FI 2 и многих других языков возможно уже знакомы с формой записи переменная++ и переменная--. Это операторы инкремента и декремента. В PHP/FI 2 операция '$a++' не имеет значения (это не выражение), и, таким образом, вы не можете присвоить ее или каким-либо образом использовать. PHP увеличивает возможности инкремента/декремента, также сделав их выражениями, как в C. Также как и C, PHP поддерживает два типа инкремента - префиксный и постфиксный. Они оба инкрементируют значение переменной и эффект их действия на нее одинаков. Разница состоит в значении выражения инкремента. Префиксный инкремент, записываемый как '++$variable', вычисляется в инкрементированное значение (PHP инкрементирует переменную перед тем как прочесть ее значение, отсюда название 'пре-инкремент'). Постфиксный инкремент, записываемый как '$variable++', вычисляется в первоначальное значение переменной $variable перед ее приращением (PHP инкрементирует переменную после прочтения ее значения, отсюда название 'пост-инкремент'). Очень распространенным типом выражений являются выражения сравнения. Они вычисляются в 0 или 1, означающих соответственно FALSE (ложь) или TRUE (истину). PHP поддерживает > (больше), >= (больше либо равно), == (равно), != (не равно), < (меньше) и <= (меньше либо равно). Он также поддерживает операторы строгого равенства: === (равно и одного типа) и !== (не равно или не одного типа). Чаще всего эти выражения используются в условиях выполнения операторов, таких как if. Последний пример выражений, который мы здесь рассмотрим, это смешанные выражения операции и присвоения. Вы уже знаете, что если вы хотите увеличить $a на 1, вы можете просто написать '$a++' или '++$a'. Но что, если вы хотите прибавить больше, чем единицу, например, 3? Вы могли бы написать '$a++' много раз, однако, очевидно это не очень рациональный или удобный способ. Гораздо более распространенной практикой является запись вида '$a = $a + 3'. '$a + 3' вычисляется в значение $a плюс 3 и снова присваивается $a, увеличивая в результате $a на 3. В PHP, как и в некоторых других языках, таких как C, вы можете записать это более коротким образом, что увеличит очевидность смысла и быстроту понимания кода по прошествии времени. Прибавить 3 к текущему значению $a можно с помощью записи '$a += 3'. Это означает дословно "взять значение $a, прибавить к нему 3 и снова присвоить его переменной $a". Кроме большей понятности и краткости, это быстрее работает. Значением '$a += 3', как и обычного присвоения, является присвоенное значение. Обратите внимание, что это НЕ 3, а суммированное значение $a плюс 3 (то, что было присвоено $a). Таким образом может использоваться любой двухместный оператор, например, '$a -= 5' (вычесть 5 из значения $a), '$b *= 7' (умножить значение $b на 7) и т.д. Существует еще одно выражение, которое может выглядеть необычным, если вы не встречали его в других языках - тернарный условный оператор: Если значением первого подвыражения является TRUE (не ноль), выполняется второе подвыражение, которое и будет результатом условного выражения. В противном случае, будет выполнено третье подвыражение и его значение будет результатом. Следующий пример должен помочь вам немного улучшить понимание префиксного и постфиксного инкремента и выражений: <?php
function double($i) { return $i*2; } $b = $a = 5; /* присвоить значение пять переменным $a и $b */ $c = $a++; /* постфиксный инкремент, присвоить значение $a (5) переменной $c */ $e = $d = ++$b; /* префиксный инкремент, присвоить увеличенное значение $b (6) переменным $d и $e */ /* в этой точке и $d, и $e равны 6 */ $f = double($d++); /* присвоить удвоенное значение $d перед инкрементом (2*6 = 12) переменной $f */ $g = double(++$e); /* присвоить удвоенное значение $e после инкремента (2*7 = 14) переменной $g */ $h = $g += 10; /* сначала переменная $g увеличивается на 10, приобретая, в итоге, значение 24. Затем значение присвоения (24) присваивается переменной $h, которая в итоге также становится равной 24. */ ?> Некоторые выражения могут рассматриваться как инструкции. В данном случае инструкция имеет вид 'выражение' ';' - выражение с последующей точкой с запятой. В записи '$b=$a=5;', $a=5 - это верное выражение, но само по себе не инструкция. Тогда как '$b=$a=5;' является верной инструкцией. Последнее, что стоит упомянуть, это истинность значения выражений. Во многих случаях, как правило, в условных операторах и циклах, вас может интересовать не конкретное значение выражения, а только значат ли они TRUE или FALSE. Константы TRUE и FALSE (регистро-независимые) - это два возможных булевых значения. При необходимости выражение автоматически преобразуется в булев тип. Подробнее о том, как это происходит, смотрите в разделе о приведении типов. PHP предоставляет полную и мощную реализацию выражений, и их полное документирование выходит за рамки этого руководства. Вышеприведенные примеры должны дать вам представление о том, что они из себя представляют и как вы сами можете создавать полезные выражения. Далее, для обозначения любого верного выражения PHP в этой документации мы будем использовать сокращение expr. Содержание Вступление Общие рассуждения Если PHP установлен как CGI Если PHP установлен как модуль Apache Безопасность файловой системы Безопасность баз данных Сообщения об ошибках Использование глобальных переменных (Register_Globals) Данные, введенные пользователем Сокрытие PHP Необходимость обновлений PHP является мощным языком программирования и интерпретатором, взаимодействующим с веб-сервером как модуль либо как независимое бинарное CGI приложение. PHP способен обращаться к файлам, выполнять различные команды на сервере и открывать сетевые соединения. Именно поэтому все скрипты, исполняемые на сервере являются потенциально опасными. PHP изначально разрабатывался как более защищенный (относительно Perl, C) язык для написания CGI-приложений. При помощи ряда настроек во время компиляции, а также настроек во время работы приложения, вы всегда сможете найти подходящее сочетание свободы действий и безопасности. Поскольку существует много различных способов использования PHP, имеется и множество опций, управляющих его поведением. Широкий выбор опций гарантирует вам возможность использовать PHP в разных целях, но также означает, что некоторые комбинации опций делают сервер незащищенным. Гибкость конфигурирования PHP можно сравнить с гибкостью самого языка. PHP можно использовать для создания полноценных серверных приложений, использующих доступные для указанного пользователя возможности операционной системы, также возможна реализация включения файлов, хранящихся на сервере с минимальным риском в жестко контролируемой среде. То, насколько безопасен ваш сервер и как настроено окружение, в большей части зависит от PHP-разработчика. Эта глава начинается с рассмотрения некоторых общих вопросов безопасности, различных конфигурационных опций и их комбинаций, а также ситуаций, когда их использование является безопасным. Кроме того, приводятся некоторые рассуждения касательно безопасного кодирования. Общие рассужденияТак как абсолютно безопасные системы являются не более, чем мифом, на практике приходится балансировать между комфортом и безопасностью. Если каждая переменная, вводимая пользователем, будет требовать две биометрические проверки (например, сканирование сетчатки глаза и отпечатки пальцев), то вы получите предельно высокую достоверность данных. Но поскольку заполнение сложной формы будет занимать около получаса, у пользователей такой системы непременно возникнет желание обойти навязчивую защиту. Правильно поставленная защита должна соответствовать основным требованиям безопасности, не ухудшая при этом работу пользователя и не усложняя самому программисту разработку продукта. Вместе с тем, некоторые атаки могут основываться именно на таком подходе к защите, что приводит к ее постепенному ослаблению. Следует помнить хорошую поговорку: надежность системы определяется ее самым слабым звеном. Например, если все транзакции логируются по времени, месторасположению, типу транзакции и ряду других параметров, но авторизация пользователя происходит всего лишь по куке (cookie), то связь конкретной записи в логе с пользователем системы весьма сомнительна. При тестировании следует помнить, что вы не можете проверить все возможные варианты даже для простейшей страницы. Данные, которые вы ожидаете, могут совершенно не соответствовать тому, что введет разъяренный служащий, хакер со стажем или домашний кот, разгуливающий по клавиатуре. Поэтому лучше логически подумать над вопросом: в каком месте могут быть введены неожиданные данные, как их можно модифицировать, усечь либо, наоборот, дополнить. Интернет наполнен людьми, которые хотят сделать себе имя на том, что взломают ваш код, разрушат сайт, опубликуют на нем неуместный контент или просто сделают ваши дни интереснее. И не важно, маленький у вас сайт или большой, если у вас есть онлайн-сервер - вы уже потенциальная жертва. Многие программы-взломщики несомтрят на размер, они просто перебирают массивы IP-адресов, выискивая очередную жертву. Постарайтесь не стать одной из них. Если PHP установлен как CGIВозможные атакиИспользование PHP как бинарного CGI-приложения является одним из вариантов, когда по каким-либо причинам нежелательно интегрировать PHP в веб-сервер (например Apache) в качестве модуля, либо предполагается использование таких утилит, как chroot и setuid для организации безопасного окружения во время работы скриптов. Такая установка обычно сопровождается копированием исполняемого файла PHP в директорию cgi-bin веб-сервера. CERT (организация, следящая за угрозами безопасности) CA-96.11 рекомендует не помещать какие-либо интерпретаторы в каталог cgi-bin. Даже если PHP используется как самостоятельный интерпрктатор, он спроектирован так, чтобы предотвратить возможность следующих атак: Данные, введенные в строке запроса (URL) после вопросительного знака, передаются интерпретатору как аргументы командной строки согласно CGI протоколу. Обычно интерпретаторы открывают и исполняют файл, указанный в качестве первого аргумента. В случае использования PHP посредством CGI-протокола он не станет интерпретировать аргументы командной строки. Согласно общепринятому соглашению часть пути в запрошенной странице, которая расположена после имени выполняемого модуля PHP, /secret/doc.html, используется для указания файла, который будет интерпретирован как CGI-программа Обычно, некоторые конфигурационные опции веб-серевера (например, Action для сервера Apache) используются для перенаправления документа, к примеру, для перенаправления запросов вида http://my.host/secret/script.php интерпретатору PHP. В таком случае веб-сервер вначале проверяет права доступа к директории /secret, и после этого создает перенаправленный запрос http://my.host/cgi-bin/php/secret/script.php. К сожалению, если запрос изначально задан в полном виде, проверка на наличие прав для файла /secret/script.php не выполняется, она происходит только для файла /cgi-bin/php. Таким образом, пользователь имеет возможность обратиться к /cgi-bin/php, и, как следствие, к любому защищенному документу на сервере. В PHP, указывая во время компиляции опцию --enable-force-cgi-redirect, а таке опции doc_root и user_dir во время выполнения скрипта, можно предотвратить подобные атаки для директорий с ограниченным доступом. Более детально приведенные опции, а также их комбинации будут рассмотрены ниже. Вариант 1: обслуживаются только общедоступные файлыВ случае, если на вашем сервере отсутствуют файлы, доступ к которым ограничен паролем либо фильтром по IP-адресам, нет никакой необходимости использовать данные опции. Если ваш веб-сервер не разрешает выполнять перенаправления либо не имеет возможности взаимодействовать с исполняемым PHP-модулем на необходимом уровне безопасности, вы можете использовать опцию --enable-force-cgi-redirect во время сборки PHP. Но при этом вы должны убедиться, что альтернативные способы вызова скрипта, такие как непосредственно вызов http://my.host/cgi-bin/php/dir/script.php либо с переадресацией http://my.host/dir/script.php, недоступны. В веб-сервере Apache перенаправление может быть сконфигурировано при помощи директив AddHandler и Action (описано ниже). Вариант 2: использование --enable-force-cgi-redirectЭта опция, указываемая во время сборки PHP, предотвращает вызов скриптов непосредственно по адресу вида http://my.host/cgi-bin/php/secretdir/script.php. Вместо этого, PHP будет обрабатывать пришедший запрос только в том случае, если он был перенаправлен веб-сервером. Обычно перенаправление в веб-сервере Apache настраивается при помощи следующих опций: Action php-script /cgi-bin/php AddHandler php-script .php Эта опция проверена только для веб-сервера Apache, ее работа основывается на установке в случае перенаправления нестандартной переменной REDIRECT_STATUS, находящейся в CGI-окружении. В случае, если ваш веб-сервер не предоставляет возможности однозначно идентифицировать, является ли данный запрос перенаправленным, вы не можете использовать описываемую в данном разделе опцию и должны воспользоваться любым другим методом работы с CGI-приложениями. Вариант 3: использование опций doc_root и user_dirРазмещение динамического контента, такого как скрипты либо любые другие исполняемые файлы, в директории веб-сервера делает его потенциально опасным. В случае, если в конфигурации сервера допущена ошибка, возможна ситуация, когда скрипты не выполняются, а отображаются в браузере, как обычные HTML-документы, что может привести к утечке конфиденциальной информации (например, паролей), либо информации, являющейся интеллектуальной собственностью. Исходя из таких соображений, многие системные администраторы предпочитают использовать для хранения скриптов отдельную директорию, работая со всеми размещенными в ней файлами по CGI-интерфейсу. В случае, если невозможно гарантировать, что запросы не перенаправляются, как было показано в предыдущем разделе, необходимо указывать переменную doc_root, которая отличается от корневой директории веб-документов. Вы можете установить корневую директорию для PHP-скриптов, настроив параметр doc_root в конфигурационном файле, либо установив переменную окружения PHP_DOCUMENT_ROOT. В случае, если PHP используется посредством CGI, полный путь к открываемому файлу будет построен на основании значения переменной doc_root и указанного в запросе пути. Таким образом, вы можете быть уверены, что скрипты будут выполняться только внутри указанной вами директории (кроме директории user_dir, которая описана ниже). Еще одна используемая при настройке безопасности опция - user_dir. В случае, если переменная user_dir не установлена, путь к открываемому файлу строится относительно doc_root. Запрос вида http://my.host/~user/doc.php приводит к выполнению скрипта, находящегося не в домашнем каталоге соответствующего пользователя, а находящегося в подкаталоге doc_root скрипта ~user/doc.php (да, имя директории начинается с символа ~). Но если переменной public_php присвоено значение, например, http://my.host/~user/doc.php, тогда в приведенном выше примере будет выполнен скрипт doc.php, находящийся в домашнем каталоге пользователя, в директории public_php. Например, если домашний каталог пользователя /home/user, будет выполнен файл /home/user/public_php/doc.php. Установка опции user_dir происходит независимо от установки doc_root, таким образом вы можете контролировать корневую директорию веб-сервера и пользовательские директории независимо друг от друга. Вариант 4: PHP вне дерева веб-документовОдин из способов существенно повысить уровень безопасности - поместить исполняемый модуль PHP вне дерева веб-документов, например в /usr/local/bin. Единственным недостатком такого подхода является то, что первая строка каждого скрипта должна иметь вид: Также необходимо сделать все файлы скриптов исполняемыми. Таким образом, скрипт будет рассматриваться так же, как и любое другое CGI-приложение, написанное на Perl, sh или любом другом скриптовом языке, который использует дописывание #! в начало файла для запуска самого себя. Что бы внутри скрипта вы могли получить корректные значения переменных PATH_INFO и PATH_TRANSLATED, PHP должен быть сконфигурирован с опцией --enable-discard-path. Если PHP установлен как модуль ApacheКогда PHP используется как модуль Apache, он наследует права пользователя, с которыми был запущен веб-сервер (обычно это пользователь 'nobody'). Это влияет на обеспечение безопасности и реализацию авторизации. Например, если вы используете базу данных, которая не имеет встроенного механизма разграничения доступа, вам прийдется обеспечить доступ к БД для пользователя 'nobody'. В таком случае зловредный скрипт может получить доступ к базе данных и модифицировать ее, даже не зная логина и пароля. Вполне возможна ситуация, когда веб-паук неверными запросами страницы администратора базы данных уничтожит все данные или даже структуру БД. Вы можете избежать такой ситуации при помощи авторизации Apache или разработав собственную модель доступа, используя LDAP, файлы .htaccess или любые другие технологии, внедряя соответствующий код в ваши скрипты. Достаточно часто используются такие настройки безопасности, при которых PHP (имеется ввиду пользователь, с правами которого выполняется Apache) имеет минимальные привелегии, например отсутствует возможность записи в пользовательские директории. Или, например, отсутствует возможность работать с базой данных. При этом система безопасности не позволяет записывать как "хорошие", так и "плохие" файлы, аналогично позволяет производить как "хорошие", так и "плохие" транзакции. Распространенной ошибкой является запуск Apache с правами суперпользователя или любое другое расширение полномочий веб-сервера. Расширение привилегий веб-сервера до полномочий угрожает работоспособности всей системы, такие команды, как sudo, chroot должны выполняться исключительно теми, кто считает себя профессионалами в вопросах безопасности. Существует несколько простых решений. Используя open_basedir, вы можете ограничить дерево доступных директорий для PHP. Вы так же можете определить область доступа Apache, ограничив все веб-сервисы не-пользовательскими или не-системными файлами. PHP является одним из важных моментов в вопросе безопасности сервера, поскольку PHP-скрипты могут манипулировать файлами и каталогами на диске. В связи с этим существуют конфигурационные настройки, указывающие, какие файлы могут быть доступны и какие операции с ними можно выполнять. Необходимо проявлять осторожность, поскольку любой из файлов с соответствующими правами доступа может быть прочитан каждым, кто имеет доступ к файловой системе. Поскольку в PHP изначально предполагался полноправный пользовательский доступ к файловой системе, можно написать скрипт, который позволит читать системные файлы, такие как /etc/passwd, управлять сетевыми соединениями, отправлять задания принтеру, и так далее. Как следствие вы всегда должны быть уверены в том, что файлы, которые вы читаете или модифицируете, соответствуют вашим намерениям. Рассмотрим следующий пример, в коротом пользователь создал скрипт, удаляющий файл из его домашней директории. Предполагается ситуация, когда веб-интерфейс, написанный на PHP, регулярно используется для работы с файлами, и настройки безопасности позволяют удалять файлы в домашнем каталоге. <?php
// Удаление файла из домашней директории пользователя $username = $_POST['user_submitted_name']; $homedir = "/home/$username"; $file_to_delete = "$userfile"; unlink ("$homedir/$userfile"); echo "$file_to_delete has been deleted!"; ?> |
Поскольку переменные вводятся в пользовательской форме, существует возможность удалить файлы, принадлежащие кому-либо другому, введя соответствующие значения. В этом случае может понадобиться авторизация. Посмотрим, что произойдет, если будут отправлены значения "../etc/" и "passwd". Скрипт выполнит следующие действия:
Пример 15-2. Атака на файловую систему <?php
// Удаление любого файла, доступного из PHP-скрипта. // В случае, если PHP работает с правами пользователя root: $username = "../etc/"; $homedir = "/home/../etc/"; $file_to_delete = "passwd"; unlink ("/home/../etc/passwd"); echo "/home/../etc/passwd has been deleted!"; ?> |
Cуществуют два решения описанной проблемы.
- Ограничить доступ пользователя, с правами которого работает веб-сервер.
- Проверять все данные, вводимые пользователем.
Вот улучшеный вариант кода:
Пример 15-3. Более безопасная проверка имени файла <?php
// Удаление любого файла, доступного из PHP-скрипта. $username = $_SERVER['REMOTE_USER']; // использование авторизации $homedir = "/home/$username"; $file_to_delete = basename("$userfile"); // усечение пути unlink ($homedir/$file_to_delete); $fp = fopen("/home/logging/filedelete.log","+a"); //логируем удаление $logstring = "$username $homedir $file_to_delete"; fputs ($fp, $logstring); fclose($fp); echo "$file_to_delete has been deleted!"; ?> |
Однако и такая проверка не учитывает все возможные ситуации. Если система авторизации позволяет пользователям выбирать произвольные логины, вломщик может создать учетную запись вида "../etc/" и система опять окажется уязвимой. Исходя из этого, вам может понадобиться более строгая проверка:
Пример 15-4. Более строгая проверка имени файла <?php
$username = $_SERVER['REMOTE_USER']; // использование авторизации $homedir = "/home/$username"; if (!ereg('^[^./][^/]*$', $userfile)) die('bad filename'); //завершение работы if (!ereg('^[^./][^/]*$', $username)) die('bad username'); //завершение работы //etc... ?> |
В зависимости от используемой вами операционной системы необходимо предусматривать возможность атаки на разнообразные файлы, включая системные файлы устройств (/dev/ или COM1), конфигурационные файлы (например /etc/ или файлы с расширением .ini), хорошо известные области хранения данных (/home/, My Documents), и так далее. Исходя из этого, как правило, легче реализовать такую политику безопасности, в которой запрещено все, исключая то, что явно разрешено.
Безопасность баз данных
На сегодняшний день базы данных являются ключевыми компонентами большинства веб-приложений, позволяя предоставлять на сайтах динамический контент. Поскольку в таких БД может храниться очень точная или конфиденциальная информация, вы должны обеспечить хорошую защиту данных.
Для извлечения или сохранения любых данных вам необходимо открыть соединение с базой данных, отправить верный запрос, извлечь результат и закрыть соединение. В настоящее время наиболее распространенный стандарт общения - структурированный язык запросов (SQL). Всегда следует помнить о возможности атаки посредством SQL-запроса.
Очевидно, что сам по себе PHP не может защитить вашу базу данных. Этот раздел документации рассказывает об основах безопасного доступа и управления данными в PHP-скриптах.
Запомните простое правило: максимальная защита. Чем больше потенциально опасных участков системы вы проработаете, тем сложнее будет потенциальному взломщику получить доступ к базе данных или повредить ее. Хороший дизайн базы данных и программных приложений поможет вам справиться с вашими страхами.
Проектирование базы данных
Первый шаг - это всегда создание БД, исключая тот случай, когда вы хотите использовать готовую базу, предоставляемую третьим лицом. После того, как база данных создана, она назначается пользователю, который выполнил создавший БД запрос. Как правило, только владелец (или суперпользователь) может выполнять различные действия с различными объектами, хранимыми в базе данных. Для того, чтобы и другие пользователи имели к ней доступ, их необходимо наделить соответствующими привелегиями.
Приложения не должны соединяться с базой данных, используя учетную запись владельца или суперпользователя, иначе они смогут модифицировать структуру таблиц (например, удалить некоторые таблицы) или даже удалить все содержимое БД целиком.
Вы можете создать различные учетные записи пользователей БД для каждой индивидуальной потребности приложения с соответствующими функциональными ограничениями. Рекомендуется назначать только самые необходимые привилегии, также вы должны избегать ситуаций, когда один и тот же пользователь может взаимодействовать с базой данных в нескольких режимах. Вы должны понимать, что если злоумышленник сможет воспользоваться какой-либо учетной записью вашей БД, он сможет вносить в базу все те изменения, что и программа, которая использует текущую учетную запись.
Вам не обязательно реализовывать всю бизнес-логику в веб-приложении (т.е. в скриптах), для этого также можно использовать возможности, предоставляемые базой данных: триггеры, представления, правила. В случае роста системы вам понадобятся новые соединения с БД, и логику работы понадобиться дублировать для каждого нового интерфейса доступа. Исходя из вышесказанного, триггеры могут использоваться для прозрачной и автоматической обработки записей, что часто необходимо при отладке приложений или при трассировке отката транзакций.
Соединение с базой данных
Вы можете использовать безопасные SSL или ssh соединения, для шифрования данных, которыми обмениваются клиент и сервер. Если вы реализуете что-нибудь из этого, то мониторинг трафика и сбор данных о вашей базе данных для потенциального взломщика существенно усложнится.
Защита хранилища базы данных
SSL/SSH защищает данные, которыми обмениваются клиент и сервер, но не защищают сами данные, хранимые в базе данных. SSL - протокол шифрования на уровне сеанса передачи данных.
В случае, если взломщик получил непосредственный доступ к БД (в обход веб-сервера), он может извлечь интересующие данные или нарушить их целостность, поскольку информация не защищена на уровне самой БД. Шифрование данных - хороший способ предотвратить такую ситуацию, но лишь незначительное количество БД предоставляют такую возможность.
Наиболее простое решение этой проблемы - установить вначале обыкновенный программный пакет для шифрования данных, а затем использовать его в ваших скриптах. PHP, в таком случае, может помочь вам в работе с такими расширениями как Mcrypt и Mhash, реализующими различные алгоритмы криптования. При таком подходе скрипт вначале шифрует сохраняемые данные, а затем дешифрует их при запросе. Ниже приведены примеры того, как работает шифрование данных в PHP-скриптах.
В случае работы со скрытыми служебными данными их нешифрованное представление не требуется (т.е. не отображается), и, как следствие, можно использовать хеширование. Хорошо известный пример хэширования - хранение MD5-хеша от пароля в БД, вместо хранения оригинального значения. Более детальная информация доступна в описании функций crypt() and md5().
Пример 15-5. Использование хешированных паролей
//
сохранение хешированного пароля
$query = sprintf("INSERT INTO users(name,pwd)
VALUES('%s','%s');",
addslashes($username),
md5($password));
$result = pg_exec($connection, $query);
// проверка введенного пользователем логина и пароля на корректность
$query = sprintf("SELECT 1 FROM users WHERE name='%s' AND
pwd='%s';",
addslashes($username),
md5($password));
$result = pg_exec($connection, $query);
if (pg_numrows($result) > 0) {
echo "Welcome, $username!";
}
else {
echo "Authentication failed for
$username.";
}
SQL-инъекции
Многие веб-разработчики даже не догадываются, что SQL-запросы могут быть подделаны, и считают, что SQL-запросы всегда достоверны. На самом деле поддельные запросы могут обойти ограничения доступа, стандартную проверку авторизации, а некоторые виды запросов могут дать возможность выполнять команды операционной системы.
Принудительное внедрение вредоносных инструкций в SQL-запросы - методика, в которой взломщик создает или изменяет текущие SQL-запросы для работы со скрытыми данными, их изменения или даже выполнения опасных комманд операционной системы на сервере базы данных. Атака выполняется на базе приложения, строящего SQL-запросы из пользовательского ввода и статических переменных. Следующие примеры, к сожалению, построены на реальных фактах.
Благодаря отсутствию проверки пользовательского ввода и соединением с базой данных под учетной записью суперпользователя (или любого другого пользователя, наделенного соответствующими привелегиями), взломщик может создать еще одного пользователя БД с правами суперпользователя.
Пример 15-6. Постраничный вывод результата... и создание суперпользователя в PostgreSQL и MySQL
$offset = argv[0]; // проверка пользовательских данных отсутствует
$query = "SELECT id, name FROM products ORDER BY
name LIMIT 20 OFFSET $offset;";
// используя PostgreSQL
$result = pg_exec($conn, $query);
// используя MySQL
$result = mysql_query($query);
Обычно пользователи кликают по ссылкам 'вперед' и 'назад', вследствии чего значение переменной $offset заносится в адресную строку. Скрипт ожидает, что $offset - десятиричное число. Однако, взломщик может попытаться взломать систему, присоединив к строке запроса дополнительную подстроку, обработанную функцией urlencode():
// используя PostgreSQL
0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
select 'crack', usesysid, 't','t','crack'
from pg_shadow where usename='postgres';
--
// используя MySQL
0;
UPDATE user SET Password=PASSWORD('crack') WHERE user='root';
FLUSH PRIVILEGES;
Если это произойдет, скрипт предоставит взломщику доступ к базе с правами суперпользователя. Заметим, что 0; использован для того, чтобы задать правильное значение смещения для первого запроса и корректно его завершить.
Замечание: Уже привычна технология, когда разработчики указывают принудительное игнорирование парсером SQL оставшейся части запроса при помощи нотации --, означающей комментарий.
Еще один вероятный способ получить пароли учетных записей в БД - атака страниц, предоставляющих поиск по базе. Взломщику нужно лишь проверить, используется ли в запросе передаваемая на сервер и необрабатываемая надлежащим образом переменная. Это может быть один из устанавливаемых на предыдущей странице фильтров, таких как WHERE, ORDER BY, LIMIT и OFFSET, используемых при построении запросов SELECT. В случае, если используемая вами база данных поддерживает конструкцию UNION, взломщик может присоединить к оригинальному запросу еще один дополнительный, для извлечения пользовательских паролей. Настоятельно рекомендуем использовать только зашифрованные пароли.
Пример 15-7. Листинг статей... и некоторых паролей (для любой базы данных)
$query = "SELECT id, name,
inserted, size FROM products
WHERE
size = '$size'
ORDER
BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);
Статическая часть запроса может комбинироваться с другим SQL-запросом, который откроет все пароли:
Если этот запрос (использующий ' и --) присоединить к значению одной из переменных, используемых для формирования $query, запрос заметно преобразится.
Команды UPDATE также могут использоваться для атаки. Опять же, есть угроза разделения инструкции на несколько запросов, присоединения дополнительного запроса. Также взломщик может видоизменить выражение SET. В этом случае потенциальному взломщику необходимо обладать некоторой дополнительной информацией для успешного манипулирования запросами. Эту информацию можно получить, проанализировав используемые в форме имена переменных либо просто перебирая все наиболее распространенные варианты названия соответствующих полей (а их не так уж и много).
Пример 15-8. От восстановления пароля... до получения дополнительных привилегий (для любой базы данных)
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
Но злоумышленник может ввести значение ' or uid like'%admin%'; -- для переменной $uid для изменения пароля администратора или просто присвоить переменной $pwd значение "hehehe', admin='yes', trusted=100 " (с завершающими пробелами) для получения дополнительных привелегий. При выполнении запросы переплетаются:
// $uid == ' or uid
like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like
'%admin%'; --";
// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes',
trusted=100 WHERE ...;"
Пугающий пример того, как на сервере баз данных могут выполняться команды операционной системы.
Пример 15-9. Выполнение команд операционной системы на сервере (для базы MSSQL)
$query = "SELECT * FROM products
WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
Если взломщик введет значениме a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- для переменной $prod, тогда запрос $query будет выглядеть так:
$query =
"SELECT * FROM products
WHERE
id LIKE '%a%'
exec
master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
MSSQL сервер выполняет SQL-команды в пакетном режиме, в том числе и операции по заведению локальных учетных записей базы данных. В случае, если приложение работает с привилегиями администратора и сервис MSSQL запущен с необходимыми привилегиями, выполнив приведенные выше действия, взломщик получит аккаунт для доступа к серверу.
Замечание: Некоторые приведенные в этой главе примеры касаются конкретной базы данных. Это не означает, что аналогичные атаки на другие программные продукты невозможны. Работоспособность вашей базы данных может быть нарушена каким-либо другим способом.
Способы защиты
Вы можете утешать себя тем, что в большинстве случаев, взломщик должен обладать некоторой информацией о структуре базы данных. Вы правы, но вы не знаете, когда и как будет предпринята попытка взлома, в случае если это произойдет ваша БД окажется незащищенной. Если вы используете программный продукт с открытыми исходными кодами или просто общедоступный пакет для работы с базой данных (например контент менеджер или форум), взломщик легко сможет воспроизвести интересующие его участки кода. В случае если они плохо спроектированы, это может являться одной из угроз вашей безопасности.
Большинство успешных атак основывается на коде, написанном без учета соответствующих требований безопасности. Не доверяйте никаким вводим данным, особенно если они поступают со стороны клиента, даже если это списки в форме, скрытые поля или куки. Приведенные примеры показывают, к каким последствиям могут привести подделанные запросы.
Пример 15-10. Более безопасная реализация постраничной навигации
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20
OFFSET $offset;";
//
обратите
внимание
на
формат
%d,
использование
%s
было
бы
бессмысленно
$query = sprintf("SELECT id, name FROM products ORDER BY name
LIMIT 20 OFFSET %d;",
$offset);
- Экранируйте любой нецифровой ввод, используемый в запросах к БД при помощи функций addslashes() или addcslashes(). Обратите внимание на первый пример. Следует помнить, что одного использования кавычек в запросе мало, это легко обойти.
- Не выводите никакой информации о БД, особенно о ее структуре. Также ознакомьтесь с соответствующими разделами документации: Сообщения об ошибках и Функции обработки и логирования ошибок.
- Вы можете использовать хранимые процедуры и заранее определенные курсоры для абстрагированной работы с данными, не предоставляя пользователям прямого доступа к данным и представлениям, но это решение имеет свои особенности.
Помимо всего вышесказанного, вы можете логировать запросы в вашем скрипте либо на уровне базы данных, если она это поддерживает. Очевидно, что логирование не может предотвратить нанесение ущерба, но может помочь при трассировке взломанного приложения. Лог-файл полезен не сам по себе, а информацией, которая в нем содержится. Причем, в большинстве случаев полезно логировать все возможные детали.
С точки зрения безопасности вывод сообщений об ошибках несет в себе как плюсы, так и минусы.
Одна из стандартных методик, применяемых в атаках - ввод некорректных данных с последующим анализом содержания и характера сообщений об ошибках. Это дает взломщику возможность проверить скрипты и данные сервера на наличие потенциальных дыр. Например, если взломщик получил некоторую информацию о странице на основании отправки формы, он попробует предопределить некоторые передаваемые значения или модифицировать их:
Пример 15-11. Атака на переменные в HTML-странице
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>
Возникаемые во время работы скриптов ошибки являются достаточно ценной информацией для разработчика, содержащей такие данные, как функция или файл, а также номер строки, в которой возникла ошибка. Вся эта информация может быть использована для взлома. Для PHP-разработчика достаточно привычно пользоваться такими функциями, как show_source(), highlight_string() или highlight_file() в целях отладки, но в живых сайтах это может открыть информацию о скрытых переменных, непроверяемом синтаксисе и других потенциально опасных моментах. Особенно опасно наличие кода со встроенным механизмом отладки в публичных частях сайта. Взломщик может попытаться запустить отладочный механизм, подбирая основные признаки отладки:
Пример 15-12. Использование стандартных отладочных переменных
<input type="hidden" name="errors" value="Y" />
<input type="hidden" name="showerrors" value="1" />
<input type="hidden" name="debug" value="1" />
</form>
Независимо от метода обработки ошибок возможность проверки системы на наличие ошибок снабжает взломщика дополнительной информацией.
Например, стандартный вывод об ошибке указывает операционную систему, в которой выполняются PHP скрипты. Если взломщик анализирует обыкновенную HTML-страницу, пытаясь найти уязвимые места, используя ввод неверных данных он может обнаружить использование PHP скриптов в данной системе.
Также уведомление об ошибке может дать информацию о том, какая база данных используется, или, к примеру, как построена логика работы скриптов. Это, в свою очередь, может позволить взломщику подключиться к открытому порту базы данных либо найти специфичные ошибки в коде. Пробуя поочередно различные неверные блоки данных, злоумышленник может определить порядок аутентификации в скрипте (например, по номерам строк с ошибками) или проверять на наличие дыр различные участки кода.
Вывод стандартных ошибок, связанных с файловой системой, может указать, с какими привелегиями запущен веб-сервер, и как организованы каталоги сайта. Обработка подобных ошибок, написанная разработчиками приложения, может только усугубить проблему, если взломщиком будет найден способ обнаружить "скрытую" отладочную информацию.
Существует три основныч способа решения этой проблемы. Первый заключается в том, чтобы структурировать все функции и попытаться компенсировать объем выдаваемых ошибок. Второй способ - полностью отключить в работающем коде вывод сообщений об ошибках. И, наконец, третий способ - использовать специальные средства PHP для создания собственного обработчика ошибок. В зависимости от используемой вами политики безопасности вы можете применять в вашей конкретной ситуации все три способа.
Один из возможных способов обезопасить ваш код перед его публикацией для общего доступа - индивидуальное использование error_reporting(), чтобы выявить потенциально опасные переменные. Тестируя код перед выпуском релиза при помощи значения E_ALL, вы достаточно легко можете обнаружить участки кода, в которых переменные могут быть подменены либо модифицированы. После окончания тестирования, установив значение E_NONE, вы можете полностью отключить вывод сообщений об ошибках.
Пример 15-13. Поиск потенциально опасных переменных при помощи E_ALL
if ($username) { // Переменная не инициализируется перед использованием
$good_login = 1;
}
if ($good_login == 1) { // Если предыдущая проверка потерпела неудачу, переменная оказывается неинициализированной
readfile ("/highly/sensitive/data/index.html");
}
?>
Использование глобальных переменных (Register_Globals)
Наверное, наиболее спорным моментом в разработке PHP стала замена значения по умолчанию для опции register_globals с ON на OFF в версии 4.2.0. Большинство пользователей доверились разработчикам, даже не зная, что это за опция и как она влияет на работу PHP. Эта страница документации призвана показать, как эта настройка сочетается с вопросами безопасности при разработке приложений. Следует понимать, что сама по себе эта опция никак не влияет на безопасность, ургозу представляет некорректное использование предоставляемых ею возможностей.
В случае, если значение параметра register_globals ON, перед выполнением вашего кода будут инициализированы различные переменные, например, переменные, переданные при отправке формы. Также, учитывая тот факт, что PHP не требует инициализации переменных, написать потенциально опасный код очень легко. Это было очень спорным решением, но общество разработчиков PHP решило изменить значение по умолчанию этой директивы на OFF. В противном случае при написании кода разработчики не могли бы с уверенностью сказать, откуда пришла та или иная переменная и насколько она достоверна. До такого нововведения переменные, определяемые разработчиком внутри скрипта, и передаваемые пользователем внешние данные могли перемешиваться. Приведем простой пример злоупотребления конфигурационной опцией register_globals:
Пример 15-14. Пример опасного кода с register_globals = on
// устанавливаем переменную $authorized = true только для пользователей, прошедших авторизацию
if (authenticated_user()) {
$authorized = true;
}
// Поскольку в случае неудачи при проверке авторизации переменная $authorized
// не установлена, она может быть установлена автоматически, благодаря register_globals,
// например, при GET запросе GET auth.php?authorized=1.
// Таким образом, пройти эту проверку можно без авторизации
if ($authorized) {
include "/highly/sensitive/data.php";
}
?>
В случае register_globals = on логика работы скрипта может быть нарушена. В случае, если установленное значение off, переменная $authorized не может быть установлена из внешних данных запроса, и скрипт будет работать корректно. Но все же инициализация переменных - один из признаков хорошего тона в программировании. Например, в приведенном выше участке кода мы могли поместить $authorized = false в качестве первой строки. Такой код работал бы как со значением on, так и off опции register_globals, и подразумевая, что по умолчанию пользователь не проходил авторизацию.
Приведем еще один пример, использующий сессии. В случае, если register_globals = on, мы можем использовать переменную $username в приведенном ниже примере, но тогда у нас не будет уверенности в достоверности ее значения (к примеру, она могла быть передана в GET-запросе).
Пример 15-15. Пример использования сессий со значением register_globals on или off
// Мы не знаем, откуда получена переменная $username, но точно знаем, что
// переменная $_SESSION хранит в себе данные сессии
if (isset($_SESSION['username'])) {
echo "Hello <b>{$_SESSION['username']}</b>";
} else {
echo "Hello <b>Guest</b><br />";
echo "Would you like to login?";
}
?>
Также существует возможность реализации оперативного реагирования в случае попытки подмены переменных. Так как во время разработки приложения мы знаем ожидаемое значение переменной, а также знаем ее достоверное значение, мы можем их сопоставить. Это не защитит код от подмены переменных, но усложнит перебор возможных вариантов. Если вы не хотите знать, как именно были получены внешние данные, используйте переменную $_REQUEST, которая состоит из данных GET и POST запросов, а также данных COOKIE. Также, информацию об этом можно найти в разделе внешние данные в PHP.
Пример 15-16. Обнаружение попытки подмены переменных
if (isset($_COOKIE['MAGIC_COOKIE'])) {
// MAGIC_COOKIE получена из достоверного источника.
// Для полной уверенности необходимо проверить ее значение.
} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {
mail("admin@example.com", "Обнаружена попытка взлома", $_SERVER['REMOTE_ADDR']);
echo "Обнаружено нарушение безопасности, администратор уведомлен.";
exit;
} else {
// MAGIC_COOKIE в данных запроса не присутствует
}
?>
Следует понимать, что установка register_globals в off не сделает ваш код безопасным. Каждую полученную от пользователя переменную следует проверять на соответствие ожидаемому значению. Всегда проверяйте ввод пользователя и инициализируйте все используемые переменные. Для проверки на наличие неинициализированных переменных можно включить в опцию error_reporting() отображение ошибок категории E_NOTICE.
Суперглобальные переменные: замечание о доступности: Начиная с PHP 4.1.0, стали доступными суперглобальные массивы, такие как $_GET, $_POST, $_SERVER и т.д. Дополнительную информацию смотрите в разделе руководства superglobals
Данные, введенные пользователем
Наиболее опасные дыры во многих PHP-скриптах возникают не столько из-за самого языка, сколько из-за кода, написанного без учета соответствующих требований безопасности. Как следствие, вы всегда должны выделять время на исследование разрабатываемого участка кода, чтобы оценить потенциальную угрозу от ввода переменной с нестандартным значением.
Пример 15-17. Потенциально опасное использование переменных
// удалить файлы из домашней директории пользователя...
// а может, еще что нибудь?
unlink ($evil_var);
// записать в лог-файл выполняемое действие...
// может быть, даже /etc/passwd?
fputs ($fp, $evil_var);
// выполнение тривиальных действий... или rm -rf *?
system ($evil_var);
exec ($evil_var);
?>
Вы должны тщательно проверять ваш код и быть абсолютно уверены в том, что все данные, передаваемые веб-браузером, проверяются надлежащим образом. Попробуйте ответить для себя на следующие вопросы:
- Будет ли данный скрипт воздействовать исключительно на предполагаемые данные?
- Правильно ли будут обработаны некорректные или нестандартные данные?
- Возможно ли использование скрипта не предусмотренным способом?
- Возможно ли его использование в сочетании с другими скриптами в негативных целях?
- Будет ли каждая транзакция корректно логирована?
Ответив на эти вопросы во время написания скрипта, а не после, вы, возможно, предотвратите последующую доработку скрипта в целях повышения его безопасности. Начиная разработку с этих вопросов, вы не гарантируете полную безопасность вашей системы, но сможете значительно повысить её.
Вы также можете предусмотреть отключение таких конфигурационных опций, как register_globals, magic_quotes и некоторых других, которые могут приводить к сомнениям относительно происхождения или значения получаемых переменных. Использование при написании кода режима error_reporting(E_ALL) может помочь, предупреждая вас об использовании переменных до инициализации или проверки (что предотвратит работу с данными, отличныи от ожидаемых).
В общем случае внесение неясности ненамного улучшает защищенность системы. Но бывают случаи, когда следует использовать малейшую возможность.
Несколько несложных методик могут помочь вам скрыть PHP, что усложняет работу потенциального взломщика, который пытается найти брешь в вашей системе. Установив опцию expose_php = off в конфигурационном файле php.ini, вы уменьшите количество доступной хакеру информации.
Еще одна методика заключается в настройке веб-сервера таким образом, чтобы он обрабатывал файлы с различными расширениями как PHP-скрипты. Это можно указать как в .htaccess файлах, так и конфигурационном файле Apache. В таком случае вы сможете использовать при написании кода нестандартные расширения:
Пример 15-18. Маскировка PHP под другие языки программирования
AddType application/x-httpd-php .asp .py .pl
Или скрыть его совсем:
Пример 15-19. Использование неизвестных расширений для PHP-скриптов # Теперь
PHP-скрипты могут иметь неизвестные типы файлов
AddType application/x-httpd-php .bop .foo .133t Также можно спрятать его под видом HTML-кода, что приведет к потере производительности, так как все HTML файлы будут обрабатываться как PHP-код: Пример 15-20. Маскировка PHP-кода под html-файлы # Теперь
PHP-скртпы могут выглядеть как обыкновенный HTML
AddType application/x-httpd-php .htm .html Чтобы достичь желаемого эффекта, вы должны переименовать все ваши скрипты в соответствии с выбранным вами расширением. Описанное в этом разделе документации повышение безопасности через сокрытие PHP имеет мало недостатков при небольших затратах. Необходимость обновленийPHP, как и любая другая система, все время тщательно проверяется и улучшается. Каждая новая версия содержит множество как существенных, так и мелких новшеств и доработок, которые, в том числе, касаются повышения безопасности, расширения конфигурационных возможностей, а так же стабильности вашей системы. Как и в других языках программирования, рекомендуется регулярно обновлять PHP и быть в курсе изменений, сделанных в последних версиях. |