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

Самоучитель PHP 4 - Котеров Д. В

..pdf
Скачиваний:
93
Добавлен:
24.05.2014
Размер:
4.38 Mб
Скачать

308 Часть 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)