Самоучитель PHP 4 - Котеров Д. В
..pdf308 Часть IV. Стандартные функции PHP
int quotemeta(string $str)
Часто бывает нужно гарантировать, чтобы в какой-то переменной-строке ни один символ не мог трактоваться как метасимвол. Этого можно добиться, предварив каждый из них наклонной чертой, что и делает функция quotemeta(). А именно, она "заслэшивает" следующие символы: . , \\, +, *, ? , [ ^ ] , ( $ ).
Перед | слэш почему-то не ставится. Будьте особо внимательны!
list split(string $pattern, string $string [,int $limit])
Эта функция очень похожа на explode(). Она тоже разбивает строку $string на части, но делает это, руководствуясь регулярным выражением $pattern. А именно, те участки строки, которые совпадают с этим выражением, и будут служить разделителями. Параметр $limit, если он задан, имеет то же самое значение, что и в функции explode() — а именно, возвращается список из не более чем $limit элементов, последний из которых содержит участок строки от ($limit-1)-го совпадения до конца строки.
Наверное, вы уже догадались, что функция split() работает гораздо медленнее, чем explode(). Однако она, вместе с тем, имеет впечатляющие возможности, в чем мы очень скоро убедимся. Тем не менее, не стоит применять split() там, где прекрасно подойдет explode(). Чаще всего этим грешат программисты, имеющие некоторый опыт работы с Perl, потому что в Perl для разбиения строки на составляющие есть только функция split().
list spliti(string $pattern, string $string [,int $limit])
Аналог функции split(), который делает то же самое, только при сопоставлении с регулярным выражением не учитывается регистр символов.
Примеры использования регулярных выражений
Какая же книга, описывающая (даже вкратце) регулярные выражения, обходится без примеров…. Я не буду отступать от установленных канонов, хотя, конечно, понимаю, что истинная свобода при работе с выражениями достигается только практикой. Некоторые из следующих ниже примеров выглядят довольно сложно, но, если разобраться, смысл чаще всего оказывается на поверхности.
Имя и расширение файла
Задача: для имени файла в $fname установить расширение out независимо от его предыдущего расширения.
Глава 22. Основы регулярных выражений в формате RegEx |
309 |
Решение:
$fname=ereg_Replace( '([[:alnum:]])(\\.[[:alnum:].]*)?$', '\\1.out',
$fname );
Обратите внимание на довольно интересную структуру этого выражения: мы не можем просто "привязать" его к концу строки при помощи $, что обусловлено спецификой работы RegEx. Мы также привязываем начало выражения к любой букве или цифре, которой оканчивается имя файла.
Имя каталога и файла
Цель: разбить полное имя файла $path на имя каталога $dir и и имя файла $fname. Средства:
$fname = ereg_Replace(".*[\\/]","",$path);
$dir = ereg_Replace("[\\/]?[^\\/]*$","",$path);
Проверка на идентификатор
Задача: проверить, является ли строка $id идентификатором, т. е. состоит ли она исключительно из алфавитно-цифровых символов (чтобы сделать задачу более интересной, договоримся также, что первым символом строки не может быть цифра).
Решение:
if(eregi("[a-z_][[:alnum:]]*",$id)) echo "Это идентификатор!";
Модификация тэгов
Задача: в тексте, заданном в $text, у всех тэгов <img> заменить в src расширение файла рисунка на gif, вне зависимости от того, какое расширение было у него до этого и было ли вообще.
Решение:
$text=eregi_Replace( '(<img[^>]*src="?[[:alnum:]/\\]*)(\\.[[:alnum:]]*)?', '\\1.jpg',
$text );
310 |
Часть IV. Стандартные функции PHP |
Преобразование гиперссылок
Задача: имеется текст, в котором иногда встречаются подстроки вида протокол://URL, где протокол — один из протоколов http, ftp или gopher, а URL — какой-нибудь адрес в Интернете. Нужно заместить их на HTML-эквиваленты <a href=…>…</a>.
Решение:
$w="[:alnum:]"; |
|
$p="[:punct:]"; |
|
$text=eregi_Replace( |
|
"((https?|ftp|gopher)://". |
// протокол |
"[$w-]+(\\.[$w-]+)*". |
// имя хоста |
"(/[$w+&.%]*(\\?[$w?+&%]*)?)?". // имя файла и параметры ")",
'<a href="\\1">\\1</a>', $text
);
Преобразование адресов E-mail
Задача: имеется текст, в котором иногда встречаются строки вида пользователь@хост, т. е. E-mail-адреса в обычном формате (или хотя бы большинство таких E-mail). Необходимо преобразовать их в HTML-ссылки.
Решение:
$text=eregi_Replace( |
|
'([[:alnum:]-.]+@'. |
// пользователь |
'[[:alnum:]-]+(\\.[[:alnum:]-]+)*'. |
// домен |
'(\\?([[:alnum:]?+&%]*)?)?'. |
// необязательные параметры |
')', |
|
'<a href="\\1">\\1</a>', |
|
$text |
|
); |
|
Этот пример, хоть и не безупречен, но все же преобразует правильно львиную долю адресов электронной почты.
Глава 22. Основы регулярных выражений в формате RegEx |
311 |
Выделение всех уникальных слов из текста
Задача: перед нами некоторый довольно длинный текст в переменной $text. Необходимо выделить из него все слова и оставить из них только уникальные. Результат должен быть представлен в виде списка, отсортированного в алфавитном порядке. Решение этой задачи может потребоваться, например, при написании индексирующей поисковой системы на PHP.
Решение: воспользуемся функцией split() и ассоциативным массивом.
Листинг 22.1. Отбор уникальных слов
//Эта функция выделяет из текста в $text все уникальные слова и
//возвращает их список, отсортированный в алфавитном порядке. function GetUniques($text)
{ // Сначала получаем все слова в тексте $Words=split("[[:punct:][:blank:]]+",$text); $Uniq=array(); // список уникальных слов $Test=array(); // хэш уже обработанных слов
//Проходимся по всем словам в $Words и заносим в $Uniq уникальные foreach($Words as $v) {
$v=strtolower($v); // в нижний регистр
//Слово уже нам встречалось? Если нет, то занести в $Uniq if(!@$Test[$v]) $Uniq[]=$v;
//Указать, что это слово уже обрабатывалось
$Test[$v]=1;
}
// Наконец, сортируем список sort($Uniq);
return $Uniq;
}
Данный пример довольно интересен, т. к. он имеет довольно большую функциональность при небольшом объеме. Его "сердце" — функция split() и цикл перебора слов с отбором уникальных. Мы используем алгоритм, основанный на применении ассоциативного массива для отбора уникальных элементов. Как он работает — надеюсь, ясно из комментариев.
Теперь мы можем воспользоваться функцией из листинга 22.1, например, в таком контексте:
$fname="sometext.txt";
312 |
Часть IV. Стандартные функции PHP |
$f=fopen($fname,"r"); $text=fread($f,filesize($fname)); fclose($f); $Uniq=GetUniques($text); foreach($Uniq as $v) echo "$v ";
Интересно будет отметить, что функция preg_split(), которая работает с регулярными выражениями в формате PCRE, и которую мы не рассматриваем в этой книге, показывает гораздо лучшую производительность в этом примере, чем split() — чуть ли не в 3 раза быстрее! Если вам нужна максимальная производительность, пожалуй, будет лучше воспользоваться именно ей, но прежде почитайте что-нибудь о Perl и его регулярных выражениях — напри- мер, в замечательной книге Perl Cookbook Тома Кристиансена и Ната Торкинг- тона (русское издание: "Библиотека программиста. Perl", издательство Питер, 2000).
Заключение
Конечно, можно придумать и еще множество примеров применения регулярных выражений. Вы наверняка сможете это сделать самостоятельно — особенно после некоторой практики, которая так важна для понимания этого материала.
Однако я хочу обратить ваше внимание на то, что во многих задачах как раз не обязательно применять регулярные выражения. Так, например, задачи "поставить слэш перед всеми кавычками в строке" и "заменить в строке все кавычки на "" можно и нужно решать при помощи str_replace(), а не ereg_Replace() (это существенно — раз в 20 — повысит быстродействие). Не забывайте, что регулярное выражение — некоторого рода "насилие" над компьютером, принуждение делать нечто такое, для чего он мало приспособлен. Этим объясняется медлительность механизмов обработки регулярных выражений, экспоненциально возрастающая с ростом сложности шаблона.
Глава 23
Работа с изображениями
Как мы знаем, одним из самых важных достижений WWW по сравнению со всеми остальными службами Интернета стала возможность представления в браузерах пользователей мультимедиа-информации, а не только "сухого" текста. Основной объем этой информации приходится, конечно же, на изображения.
Разумеется, было бы довольно расточительно хранить и передавать все рисунки в обыкновенном растровом формате (наподобие BMP), тем более, что современные алгоритмы сжатия позволяют упаковывать такого рода данные в сотни и более раз эффективней. Чаще всего для хранения изображений используются три формата сжатия с перечисленными ниже свойствами.
rJPEG. Идеален для фотографий, но сжатие изображения происходит с потерями качества, так что этот формат совершенно не подходит для хранения различных диаграмм и графиков.
rGIF. Позволяет достичь довольно хорошего соотношения размер/качество, в то же время не искажая изображение; применяется в основном для хранения небольших точечных рисунков и диаграмм.
rPNG. Сочетает в себе хорошие стороны как JPEG, так и GIF, но в настоящий момент ему почему-то не выражают особого доверия — скорее, по историческим причинам, из-за нежелания отказываться от GIF и т. д.
В последнее время GIF все более вытесняется форматом PNG, что связано в первую очередь с окончанием действия бесплатной лицензии изобретателя на его использование. К сожалению, для небольших изображений GIF все еще остается самым оптимальным форматом, оставляя позади (иногда далеко позади) PNG.
Зачем может понадобиться в Web-программировании работа с изображениями? Разве это не работа дизайнера?
В большинстве случаев это действительно так. Однако есть и исключения, например, графические счетчики (автоматически создаваемые картинки с отображаемым поверх числом, которое увеличивается при каждом "заходе" пользователя на страницу), или же графики, которые пользователь может строить в реальном времени — скажем, диаграммы сбыта продукции или снижения цен на комплектующие. Все эти приложения требуют как минимум умения генерировать изображения "на лету", причем с довольно большой скоростью. Чтобы этого добиться на PHP, можно применить два способа: задействовать какую-нибудь внешнюю утилиту для формирования изобра-
Глава 23. Работа с изображениями |
315 |
жения (например, известную программу fly), или же воспользоваться встроенными функциями PHP для работы с графикой. Оба способа имеют как достоинства, так и недостатки, но, пожалуй, недостатков меньше у второго метода, так что им-то мы и займемся в этой главе.
С недавнего времени все программные продукты, которые умели формировать изображения в формате GIF, переориентируются на PNG. В частности, не так давно компания, поддерживающая библиотеку GD для работы с GIF-изображениями, переписала ее код с учетом формата PNG. Так как PHP использует эту библиотеку, то поддержка GIF автоматически исключилась и из него. К счастью, в Интернете все еще можно найти старые версии GD с поддержкой GIF и, таким образом, настроить PHP для работы с этим форматом, но задумайтесь: стоит ли теперь применять GIF, если весь мир вполне успешно переходит на PNG, тем более, что его поддерживают практически все современные браузеры (четвертой версии) — а это 98% от используемого их числа...
Универсальная функция
GetImageSize()
Что же, работать с картинками приходится часто — гораздо чаще, чем может показаться на первый взгляд. Среди наиболее распространенных операций можно особо выделить одну — определение размера рисунка. Чтобы сделать программистам "жизнь раем", разработчики PHP встроили в него функцию, которая работает практически со всеми распространенными форматами изображений, в том числе с GIF, JPEG и PNG.
list GetIimageSize(string $filename [,array& $imageinfo])
Эта функция предназначена для быстрого определения в сценарии размеров (в пикселах) и формата рисунка, имя файла которого передано ей в первом параметре. Она возвращает список из четырех элементов. Первый элемент (с ключом 0) хранит ширину картинки в пикселах, второй (с ключом 1) — его высоту. Ячейка массива с ключом 2 определяется форматом изображения: 0, если это GIF, 1 в случае JPG и 2 для PNG. Следующий элемент, имеющий ключ 3, будет содержать после вызова функции строку примерно следующего вида: height=sx width=sy, где sx и sy — соответственно ширина и высота изображения. Это применение задумывалось для того, чтобы облегчить вставку данных о размере изображения в тэг <img>, который может быть сгенерирован сценарием.
316 |
Часть IV. Стандартные функции PHP |
Работа с изображениями и библиотека GD
Давайте теперь рассмотрим идею создания рисунков сценарием "на лету". Например, как мы уже замечали, это очень может пригодиться при создании сценариевсчетчиков, графиков, картинок-заголовков да и многого другого.
Для деятельности такого рода существует специальная библиотека под названием GD. Она содержит в себе множество функций (такие как рисование линий, растяжение/сжатие изображения, заливка до границы, вывод текста и т. д.), которые могут использовать программы, поддерживающие работу с данной библиотекой. PHP (со включенной поддержкой GD) как раз и является такой программой.
Поддержка GD включается при компиляции и установке PHP. Возможно, неко- торые хостинг-провайдеры ее не имеют. Выясните, работает ли PHP вашего хостера с библиотекой GD.
Пример
Начнем сразу с примера сценария, который представляет собой не HTML-страницу в обычном смысле, а рисунок PNG. То есть URL этого сценария можно поместить в тэг:
<img src=button.php?Hello+world!>
Как только будет загружена страница, содержащая указанный тэг, сценарий запустится и отобразит надпись Hello world! на фоне рисунка, лежащего в images/button.png. Полученная картинка нигде не будет храниться — она создается "на лету".
Рис. 23.1. Демонстрация возможностей вывода
TrueType-шрифтов на PHP
Глава 23. Работа с изображениями |
317 |
Листинг 23.1. Создание картинки "на лету"
<?
//Получаем строку, которую нам передали в параметрах $string=$QUERY_STRING;
//Загружаем рисунок фона с диска
$im = imageCreateFromPng("images/button.png"); // Создаем в палитре новый цвет — оранжевый $orange = imageColorAllocate($im, 220, 210, 60);
//Вычисляем размеры текста, который будет выведен $px = (imageSx($im)-7.5*strlen($string))/2;
//Выводим строку поверх того, что было в загруженном изображении imageString($im,3,$px,9,$string,$orange);
//Сообщаем о том, что далее следует рисунок PNG
Header("Content-type: image/png");
//Теперь — самое главное: отправляем данные картинки в
//стандартный выходной поток, т. е. в браузер imagePng($im);
//В конце освобождаем память, занятую картинкой imageDestroy($im);
?>
Итак, мы получили возможность "на лету" создавать стандартные кнопки с разными надписями, имея только "шаблон" кнопки.
Создание изображения
Давайте теперь разбираться, как работать с картинками в GD. Для начала нужно картинку создать — пустую (при помощи imageCreate()) или же загруженную с диска
(imageCreateFromPng(), imageCreateFromJpeg() или imageCreateFromGif(), в зависимости от того, какие форматы поддерживаются
PHP и GD).
int imageCreate(int $x, int $y)
Создает пустую картинку размером $x на $y точек и возвращает ее идентификатор. После того, как картинка создана, вся работа с ней осуществляется именно через этот идентификатор, по аналогии с тем, как мы работаем с файлом через его дескриптор.
int imageCreateGromPng(string $filename) или int imageCreateGromJpeg(string $filename) или int imageCreateGromif(string $filename)