Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Самоучитель по PHP 4

.pdf
Скачиваний:
82
Добавлен:
02.05.2014
Размер:
4.36 Mб
Скачать

Глава 23. Работа с изображениями

331

$im = imageCreate($MX,$MY);

// Создаем в палитре новые цвета

$black = imageColorHex($im, 0); // черный (тень) $back = imageColorHex($im, $b); // задний план $front = imageColorHex($im, $c); // цвет букв

//Очищаем задний план imageFill($im,0,0,$back); imageRectangle($im,0,0,$MX-1,$MY-1,$black);

//Выводим тень от текста

imagettftext($im,$s,$a,$x+2,$y+2,$black,getcwd()."/$f.ttf",$text); // Выводим текст imagettftext($im,$s,$a,$x,$y,$front,getcwd()."/$f.ttf",$text);

// Выводим рисунок в браузер

Header("Content-type: image/png"); imagePng($im);

?>

Сценарий из листинга 23.3 (назовем его ttf.php) генерирует картинку с заданным цветом заднего плана, в которую выводится указанная строка с тенью. При этом используется TrueType-шрифт, а также определяются размер строки, угол ее наклона, цвет и т. д.

Формат вызова сценария имеет следующий общий вид: ttf.php?a=Градусы&s=Размер&b=ЗаднийЦвет&c=Цвет&d=Зазор&f=Фонт&text=Текст

Ни один из этих параметров не является обязательным — в случае пропуска подставляются значения по умолчанию (см. листинг 23.3).

Необходимо заметить, что прежде, чем запускать сценарий, нужно скопировать TTFфайл со шрифтом в каталог, где расположена программа (например, взяв его из C:/WINDOWS/FONTS для платформы Windows). Параметр f задает имя этого файла без расширения, и ищется он в текущем каталоге. По умолчанию выбран шрифт

Times.

Глава 24

Управление

интерпретатором

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

Информационные

функции

Прежде всего давайте познакомимся с двумя функциями, одна из которых выводит текущее состояние всех параметров PHP, а вторая — версию интерпретатора.

int phpinfo()

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

rверсия PHP;

rопции, которые были установлены при компиляции PHP;

rинформация о дополнительных модулях;

rпеременные окружения, в том числе и установленные сервером при получении запроса от пользователя на вызов сценария;

rверсия операционной системы;

rсостояние основных и локальных настроек интерпретатора;

rHTTP-заголовки;

rлицензия PHP.

Глава 24. Управление интерпретатором

333

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

<?

phpinfo();

?>

Надо заметить, что функция phpinfo() в основном применяется при первоначальной установке PHP для проверки его работоспособности. Думаю, для других целей использовать ее вряд ли целесообразно — слишком уж много информации она выдает.

string phpversion()

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

int getlastmod()

Завершающая функция этой серии — getlastmod() — возвращает время последнего изменения файла, содержащего сценарий. Она не так полезна, как это может показаться на первый взгляд, потому что учитывает время изменения только главного файла, того, который запущен сервером, но не файлов, которые включаются в него директивами require или include. Время возвращается в формате timestamp (то есть, это число секунд, прошедших с 1 января 1970 года до момента модификации файла), и оно может быть затем преобразовано в читаемую форму, например:

echo "Последнее изменение: ".date("d.m.Y H:i.s.", getlastmod()); // Выводит что-то вроде 'Последнее изменение: 13.11.2000 11:23.12'

Настройка параметров PHP

Все параметры находятся в файле php.ini. Задаются они в формате параметр=значение, на одной строке может определяться только один параметр. Любые символы, расположенные после ; и до конца строки, игнорируются (таким образом, точка с запятой — это признак начала комментария).

Если PHP установлен как модуль Apache, применяется несколько другой способ конфигурирования. Можно задавать настройки PHP в главном конфигурационном файле сервера httpd.conf или в файлах .htaccess. Только для этого перед именем каждого параметра нужно поставить префикс php_ и, конечно же, как это принято в Apache, разделять имя параметра и его значение не знаком равенства, а пробелом.

Некоторые из следующих далее настроек можно переопределить в сценарии с помощью специальных функций (такой, например, как Error_Reporting()), некоторые — нельзя. За полным списком настроечных директив PHP обращайтесь к При-

ложению 2.

334

Часть IV. Стандартные функции PHP

error_reporting

Устанавливает уровень строгости для системы контроля ошибок PHP. Значение этого параметра должно представлять из себя целое число, которое интерпретируется как десятичное представление двоичной битовой маски. Установленные в 1 биты задают, насколько детальным должен быть контроль. Можно также не возиться с битами, а использовать константы.

 

 

Таблица 24.1. Биты, управляющие контролем ошибок

 

 

 

Бит

Константа PHP

Назначение

 

 

 

1

E_ERROR

Фатальные ошибки

2

E_WARNING

Общие предупреждения

4

E_PARSE

Ошибки трансляции

8

E_NOTICE

Предупреждения

16

E_CORE_ERROR

Глобальные предупреждения (почти не используются)

32

E_CORE_WARNING

Глобальные ошибки (не используется)

Наиболее часто встречающееся сочетание — 7 (1+2+4), которое, как мы можем видеть, задает полный контроль, кроме некритичных предупреждений интерпретатора (таких, например, как обращение к неинициализированной переменной). Оно часто задается по умолчанию при установке PHP. Я же рекомендую первым делом устанавливать значение этой настройки равным 255 (соответствует битовой маске со всеми единичками), т. е. включить абсолютно все сообщения об ошибках, или же воспользоваться константой E_ALL, делающей то же самое.

magic_quotes_gpc on|off

Эта настройка указывает PHP, нужно ли ему ставить дополнительный слэш перед всеми апострофами ', кавычками ", обратными слэшами \ и нулевыми символами

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

<?

// Делаем что-нибудь, если нажата кнопка Go! ?>

<form action=<?echo $SCRIPT_NAME?> method=post>

<input type=text name=name value="<?=@HtmlSpecialChars($name)?>">

Глава 24. Управление интерпретатором

335

<input type=text name=email value="<?=@HtmlSpecialChars($email)?>"> <input type=submit name=submit value="Go!">

</form>

Мы получаем явно не то, что требовалось: мы хотели просто, чтобы значение поля text сохранялось неизменным между запусками сценария. Оператор @ подавляет сообщение об ошибке для следующего за ним выражения, если она происходит (в нашем случае — при первом запуске сценария, когда переменные $name и $email еще не инициализированы).

max_execution_time

Директива устанавливает время (в секундах), через которое работа сценария будет принудительно прервана. Используется она в основном для того, чтобы запретить пользователям захватывать слишком много ресурсов центрального процессора и избежать "зависания" сценария.

track_vars on|off

Этот параметр очень полезен при программировании. Если он установлен в On, все данные, доставленные методами GET и POST, а также Cookies, будут дополнительно помещены в глобальные массивы $HTTP_GET_VARS, $HTTP_POST_VARS и $HTTP_COOKIE_VARS соответственно.

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

ложении 2 или на сайте http://www.php.net.

Контроль ошибок

В процессе работы программы в ней могут возникать ошибки. Одна из самых сильных черт PHP — возможность отображения сообщений об ошибках прямо в браузере, не генерируя пресловутую 500-ю Ошибку сервера (Internal Server Error), как это делают другие языки. В зависимости от состояния интерпретатора сообщения будут либо выводиться в браузер, либо подавляться. Для установки режима вывода ошибок служит функция Error_Reporting().

int Error_Reporting([int $level])

Устанавливает уровень строгости для системы контроля ошибок PHP, т. е. величину параметра error_reporting в конфигурации PHP, который мы недавно рассматривали. Рекомендую первой строкой сценария ставить вызов:

Error_Reporting(1+2+4+8);

336

Часть IV. Стандартные функции PHP

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

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

Оператор отключения ошибок

Есть и еще один аргумент за то, чтобы всегда использовать полный контроль ошибок. Это — существование в PHP оператора @. Если этот оператор поставить перед любым выражением, то все ошибки, которые там возникнут, будут проигнорированы. Например:

if(!@filemtime("notextst.txt")) echo "Файла не существует!";

Попробуйте убрать оператор @ — тут же получите сообщение: "Файл не найден", а только после этого — вывод оператора echo. Однако с оператором @ предупреждение будет подавлено, что нам и требовалось.

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

// Обновить файл, если его не существует или он очень старый if(!file_exists($fname) || filemtime($fname)<time()-60*60)

MyFunctionForUpdateFile($fname);

Сравните со следующим фрагментом:

// Обновить файл, если его не существует или он очень старый if(@filemtime($fname)<time()-60*60)

MyFunctionForUpdateFile($fname);

Всегда помните об операторе @. Он крайне удобен. Подумайте, стоит ли рисковать, устанавливая слабый контроль ошибок при помощи Error_reporting(), если его и так можно локально установить при помощи @? По-моему, нет.

Глава 24. Управление интерпретатором

337

Пример использования оператора @

Вот еще один полезный пример использования оператора @. Пусть у нас имеется форма с submit-кнопкой, и нам нужно в сценарии определить, нажата ли она. Мы можем сделать это так:

<?

if(!empty($submit)) echo "Кнопка нажата!";

. . .

?>

Но, согласитесь, следующий код куда элегантнее:

<?

if(@$submit) echo "Кнопка нажата!" ?>

<form action=<?=$SCRIPT_NAME?> method=post> <input type=submit name=submit value="Go!"> </form>

Старайтесь чаще пользоваться оператором @ и реже — установкой слабого контроля ошибок.

Принудительное завершение программы

void exit()

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

void die(string $message)

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

Полезным примером применения die() может служить такой код:

$filename='/path/to/data-file';

$file=fopen($filename, 'r') or die("не могу открыть файл $filename!");

Здесь мы ориентируемся на специфику оператора or — "выполнять" второй операнд только тогда, когда первый "ложен". Мы уже встречались с этим приемом в главе, посвященной работе с файлами. Заметьте, что оператор || здесь применять нельзя — он имеет более высокий приоритет, чем =. С использованием || последний пример нужно было бы переписать следующим образом:

338

Часть IV. Стандартные функции PHP

$filename='/path/to/data-file';

($file=fopen($filename, 'r')) || die("не могу открыть файл $filename!");

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

Финализаторы

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

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

Register_shutdown_function().

int Register_shutdown_function(string $func)

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

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

Правда, есть одно "но". Финальная функция вызывается уже после закрытия соединения с браузером клиента. Поэтому все данные, выведенные в ней через echo, теряются (во всяком случае, так происходит в Unix-версии PHP, а под Windows CGI-версия PHP и echo работают прекрасно). Так что лучше не выводить никаких данных в такой функции, а ограничиться работой с файлами и другими вызовами, которые ничего не направляют в браузер.

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

Глава 24. Управление интерпретатором

339

Генерация кода во время выполнения

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

Выполнение кода

int eval(string $code)

Эта функция делает довольно интересную вещь: она берет параметр $st и, рассматривая его как код программы на PHP, запускает. Если этот код возвратил какое-то значение оператором return (как, например, это обычно делают функции), eval() также вернет эту величину.

Параметр $st представляет собой обычную строку, содержащую участок PHPпрограммы. То есть в ней может быть все, что допустимо в сценариях:

rввод-вывод, в том числе закрытие и открытие тэгов <? и ?>;

rуправляющие инструкции: циклы, условные операторы и т. д.;

rобъявления и вызовы функций;

rвложенные вызовы функции eval().

Тем не менее, нужно помнить несколько важных правил.

rКод в $st будет использовать те же самые глобальные переменные, что и вызвавшая программа. Таким образом, переменные не локализуются внутри eval().

rЛюбая критическая ошибка (например, вызов неопределенной функции) в коде строки $st приведет к завершению работы всего сценария (разумеется, сообщение об ошибке также напечатается в браузер). Это значит, что мы не можем перехватить все ошибки в коде, вставив его в eval().

Последний факт вызывает довольно удручающие мысли. К сожалению, разра- ботчики PHP опять не задумались о том, как было бы удобно, если бы eval() при ошибке в вызванном ей коде просто возвращала значение false, поме- щая сообщение об ошибке в какую-нибудь переменную (как это сделано, на- пример, в Perl).

340

Часть IV. Стандартные функции PHP

rТем не менее, синтаксические ошибки и предупреждения, возникающие при трансляции кода в $st, не приводят к завершению работы сценария, а всего лишь вызывают возврат из eval()значения ложь. Что ж, хоть кое-что.

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

eval("$a=$b;"); // Неверно!

//Вы, видимо, хотели написать следующее: eval("\$a=\$b");

//но короче будет так:

eval('$a=$b');

Возможно, вы спросите: зачем нам использовать eval(), если она занимается лишь выполнением кода, который мы и так можем написать прямо в нужном месте программы? Например, следующий фрагмент

eval('for($i=0; $i<10; $i++) echo $i; ');

эквивалентен такому коду:

for($i=0; $i<10; $i++) echo $i;

Почему бы всегда не пользоваться последним фрагментом? Да, конечно, в нашем примере лучше было бы так и поступить. Однако сила eval() заключается прежде всего в том, что параметр $st может являться (и чаще всего является) не статической строковой константой, а сгенерированной переменной. Вот, например, как мы можем создать 100 функций с именами Func1()...Func100(), которые будут печатать квадраты первых 100 чисел:

Листинг 24.1. Генерация семейства функций

for($i=1; $i<=100; $i++)

eval("function Func$i() { return $i*$i; }");

Попробуйте-ка сделать это, не прибегая к услугам eval()!

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

Parse error: parse error in eval.php(4) : eval()'d code on line 1