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

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

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

218

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

Преобразование кодировок

Часто встречается ситуация, когда нам требуется преобразовать строку из одной кодировки кириллицы в другую. Например, мы в программе сменили локаль: была кодировка windows, а стала — KOI8-R. Но строки-то остались по-прежнему в кодировке WIN-1251, а значит, для правильной работы с ними нам нужно их перекодировать в KOI8-R. Для этого и служит функция преобразования кодировок.

string convert_cyr_string(string $str, char $from, char $to);

Функция переводит строку $str из кодировки $from в кодировку $to. Конечно, это имеет смысл только для строк, содержащих "русские" буквы, т. к. латиница во всех кодировках выглядит одинаково. Разумеется, кодировка $from должна совпадать с истинной кодировкой строки, иначе результат получится неверным. Значения $from и $to — один символ, определяющий кодировку:

rk — koi8-r

rw — windows-1251

ri — iso8859-5

ra — x-cp866

rd — x-cp866

rm — x-mac-cyrillic

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

Функции форматных преобразований

Как мы знаем, переменные в строках PHP интерполируются, поэтому практически всегда задача "смешивания" текста со значениями переменных не является проблемой. Например, мы можем спокойно написать что-то вроде:

echo "Привет, $name! Вам $age лет.";

Вспомните, что в Си нам приходилось для аналогичных целей писать следующий код:

printf("Привет, %s! Вам %s лет",name,age);

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

string sprintf(string $format [, mixed args, ...])

Эта функция — аналог функции sprintf() в Си. Она возвращает строку, составленную на основе строки форматирования, содержащей некоторые специальные сим-

Глава 12. Строковые функции

219

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

Строка форматирования $format может включать в себя команды форматирования, предваренные символом %. Все остальные символы копируются в выходную строку как есть. Каждый спецификатор формата (то есть, символ % и следующие за ним команды) соответствует одному, и только одному параметру, указанному после параметра $format. Если же нужно поместить в текст % как обычный символ, необходимо его удвоить:

echo sprintf("The percentage was %d%%",$percentage);

Каждый спецификатор формата включает максимум пять элементов (в порядке их следования после символа %):

rНеобязательный спецификатор размера поля, который указывает, сколько символов будет отведено под выводимую величину. В качестве символов-заполнителей (если значение имеет меньший размер, чем размер поля для его вывода) может использоваться пробел или 0, по умолчанию подставляется пробел. Можно задать любой другой символ-наполнитель, если указать его в строке форматирования, предварив апострофом '. (См. примеры, как это делается.)

rОпциональный спецификатор выравнивания, определяющий, будет результат выровнен по правому или по левому краю поля. По умолчанию производится выравнивание по правому краю, однако можно указать и левое выравнивание, задав символ − (минус).

rНеобязательное число, определяющее размер поля для вывода величины. Если результат не будет в поле помещаться, то он "вылезет" за края этого поля, но не будет усечен.

rНеобязательное число, предваренное точкой ".", предписывающее, сколько знаков после запятой будет в результирующей строке. Этот спецификатор учитывается только в том случае, если происходит вывод числа с плавающей точкой, в противном случае он игнорируется.

rНаконец, обязательный (заметьте — единственный обязательный!) спецификатор типа величины, которая будет помещена в выходную строку:

b — очередной аргумент из списка выводится как двоичное целое число;

c — выводится символ с указанным в аргументе кодом;

d — целое число;

f — число с плавающей точкой;

o — восьмеричное целое число;

s — строка символов;

x — шестнадцатеричное целое число с маленькими буквами a—z;

220

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

X — шестнадцатеричное число с большими буквами A—Z.

Вот как можно указать точность представления чисел с плавающей точкой:

$money1 = 68.75; $money2 = 54.35;

$money = $money1 + $money2;

// echo $money выведет "123.1"...

$formatted = sprintf ("%01.2f", $money); // echo $formatted выведет "123.10"!

Вот пример вывода целого числа, предваренного нужным количеством нулей:

$isodate=sprintf("%04d-%02d-%02d",$year,$month,$day);

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

void printf(string $format [, mixed args, ...])

Делает то же самое, что и sprintf(), только результирующая строка не возвращается, а направляется в браузер пользователя.

string number_format(float $number, int $decimals,

string $dec_point=".", string $thousands_sep=",");

Эта функция форматирует число с плавающей точкой с разделением его на триады с указанной точностью. Она может быть вызвана с двумя или четырьмя аргументами, но не с тремя! Параметр $decimals задает, сколько цифр после запятой должно быть у числа в выходной строке. Параметр $dec_point представляет собой разделитель целой и дробной частей, а параметр $thousands_sep — разделитель триад в числе (если указать на его месте пустую строку, то триады не отделяются друг от друга).

В PHP существует еще несколько функций для выполнения форматных преобразований, среди них — sscanf() и fscanf(), которые часто применяются в Си. Однако в PHP их использование весьма ограничено: чаще всего для разбора строк оказывается гораздо выгоднее привлечь регулярные выражения или функцию explode(). Именно по этой причине я здесь не уделяю повышенного внимания этим функциям.

Работа с бинарными данными

Как мы уже знаем, строки могут содержать любые, в том числе и бинарные, данные (то есть, символы с кодами, меньшими 32). Для работы с такими строками иногда удобно использовать функции pack() и unpack().

string pack(string $format [,mixed $args, ...])

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

Глава 12. Строковые функции

221

строки $format, которая представляет собой набор однобуквенных спецификаторов форматирования — наподобие тех, которые указываются в sprintf(), но только без знака %. После каждого спецификатора может стоять число, которое отмечает, сколько информации будет обработано данным спецификатором. А именно, для форматов a, A, h и H число задает, какое количество символов будет помещено в бинарную строку из тех, что находятся в очередном параметре-строке при вызове функции (то есть, определяется размер поля для вывода строки). В случае @ оно определяет абсолютную позицию, в которую будут помещены следующие данные. Для всех остальных спецификаторов следующие за ними числа задают количество аргументов, на которые распространяется действие данного формата. Вместо числа можно указать *, в этом случае подразумевается, что спецификатор действует на все оставшиеся данные. Вот полный список спецификаторов формата:

ra — строка, свободные места в поле заполняются символом с кодом 0;

rA — строка, свободные места заполняются пробелами;

rh — шестнадцатеричная строка, младшие разряды в начале;

rH — шестнадцатеричная строка, старшие разряды в начале;

rc — знаковый байт (символ);

rC — беззнаковый байт;

rs — знаковое короткое целое (16 битов, порядок байтов определяется архитектурой процессора);

rS — беззнаковое короткое целое;

rn — беззнаковое целое (16 битов, старшие разряды в конце);

rv — беззнаковое целое (16 битов, младшие разряды в конце);

ri — знаковое целое (размер и порядок байтов определяется архитектурой);

rI — беззнаковое целое;

rl — знаковое длинное целое (32 бита, порядок байтов определяется архитектурой);

rL — беззнаковое длинное целое;

rN — беззнаковое длинное целое (32 бита, старшие разряды в конце);

rV — беззнаковое целое (32 бита, младшие разряды в конце);

rf — число с плавающей точкой (зависит от архитектуры);

rd — число с плавающей точкой двойной точности (зависит от архитектуры);

rx — символ с нулевым кодом;

rX — возврат назад на 1 байт;

r@ — заполнение нулевым кодом до заданной абсолютной позиции.

Немало, не правда ли? Вот пример использования этой функции:

222

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

// Целое, целое, все остальное — символы $bindata = pack("nvc*", 0x1234, 0x5678, 65, 66);

После выполнения приведенного кода в строке $bindata будет содержаться 6 байтов в такой последовательности: 0x12, 0x34, 0x78, 0x56, 0x41, 0x42 (в шестнадцатеричной системе счисления).

array unpack(string $format, string $data)

Функция unpack() выполняет действия, обратные pack() — распаковывает строку $data, пользуясь информацией о формате $format. Возвращает она ассоциативный массив, содержащий элементы распакованных данных. Строка $format задается немного в другом формате, чем в функции pack(), а именно, после каждого спецификатора (или после завершающего его числа) должно "впритык" следовать имя ключа в ассоциативном массиве. Разделяются параметры при помощи символа /. Например:

$array=unpack("c2chars/nint", $bindata);

В результирующий массив будут записаны элементы с ключами: chars1, chars2 и int. Как видим, если после спецификатора задано число, то к имени ключа будут добавлены номера 1, 2 и т. д., т. е. в массиве появятся несколько ключей, отличающихся суффиксами.

Когда бывают полезны функции pack() и unpack()? Например, вы считали участок GIF-файла, содержащий его размер в пикселах, и хотите преобразовать бинарную 32битную ячейку памяти в формат, понятный PHP. Или, наоборот, стремитесь работать с файлами с фиксированным размером записи. В этом случае вам и пригодятся рассматриваемые функции. Вообще говоря, функции pack() и unpack() применяются сравнительно редко. Это связано с тем, что в PHP практически все действия, которые могут потребовать работы с бинарными данными (например, анализ файла с рисунком с целью определения его размера), уже реализованы в виде встроенных функций (в нашем примере с GIF-картинкой это GetImageSize()).

Хэш-функции

string md5(string $st)

Возвращает хэш-код строки $st, основанный на алгоритме корпорации RSA Data Security под названием "MD5 Message-Digest Algorithm". Хэш-код — это просто строка, практически уникальная для каждой из строк $st. То есть вероятность того, что две разные строки, переданные в $st, дадут нам одинаковый хэш-код, стремится к нулю.

Глава 12. Строковые функции

223

 

 

 

 

 

 

Я где-то читал об одном опыте, в котором принимали участие более 1000 мощ- ных компьютеров, на протяжении года генерировавшие хэш-коды для строк, и за все время не было обнаружено ни одного совпадения MD5-кодов для раз- личных строк. Более того, математически доказано, что они могли бы с тем же результатом заниматься этим на протяжении еще нескольких тысяч лет.

В то же время, если длина строки $st может достигать нескольких тысяч символов, то ее MD5-код занимает максимум 32 символа.

Для чего нужен хэш-код и, в частности, алгоритм MD5? Например, для проверки паролей на истинность. Пусть, к примеру, у нас есть система со многими пользователями, каждый из которых имеет свой пароль. Можно, конечно, хранить все эти пароли в обычном виде, или зашифровать их каким-нибудь способом, но тогда велика вероятность того, что в один прекрасный день этот файл с паролями у вас украдут. Если пароли были зашифрованы, то, зная метод шифрования, не составит особого труда их раскодировать. Однако можно поступить другим способом, при использовании которого даже если файл с паролями украдут, расшифровать его будет математически невозможно. Сделаем так: в файле паролей будем хранить не сами пароли, а их (MD5) хэш-коды. При попытке какого-либо пользователя войти в систему мы вычислим хэш-код только что введенного им пароля и сравним его с тем, который записан у нас в базе данных. Если коды совпадут, значит, все в порядке, а если нет — что ж, извините...

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

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

int crc32(string $str)

Функция crc32() вычисляет 32-битную контрольную сумму строки $str. То есть, результат ее работы — 32-битное (4-байтовое) целое число. Эта функция работает гораздо быстрее md5(), но в то же время выдает гораздо менее надежные "хэш-коды" для строки. Так что, теперь, чтобы получить методом случайного подбора для двух разных строк одинаковые "хэш-коды", вам потребуется не триллион лет работы самого мощного компьютера, а всего лишь… год-другой. Впрочем, если не использовать генератор случайных чисел, а разобраться в алгоритме вычисления 32-битной кон-

224

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

трольной суммы, эту же задачу легко можно решить буквально за секунду, потому что алгоритм crc32 имеет неизмеримо большую предсказуемость, чем MD5.

string crypt(string $str [,string $salt])

Алгоритм шифрования DES до недавнего времени был стандартным для всех версий Unix и использовался как раз для кодирования паролей пользователей (тем же самым способом, о котором мы говорили при рассмотрении функции md5()). Но в последнее время MD5 постепенно начал его вытеснять. Это и понятно: MD5 гораздо более надежен. Рекомендую и вам везде применять md5() вместо crypt(). Впрочем, функция crypt() все же может понадобиться вам в одном случае: если вы хотите сгенерировать хэш-код для другой программы, которая использует именно алгоритм DES (например, для сервера Apache).

Хэш-код для одной и той же строки, но с различными значениями $salt (кстати, это должна быть обязательно двухсимвольная строка) дает разные результаты. Если параметр $salt пропущен, PHP сгенерирует его случайным образом, так что не удивляйтесь работе следующего примера:

$st="This is the test";

echo crypt($st)."<br>"; // можем получить, например, 7N8JKLKbBWEhg echo crypt($st)."<br>"; // а здесь появится, например, Jsk746pawBOA2

Как видите, два одинаковых вызова crypt() без второго параметра выдают совершенно разные хэш-коды. За деталями работы функции обращайтесь к документации

PHP.

Сброс буфера вывода

void flush()

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

Глава 13

Работа с массивами

В части III книги мы уже рассматривали многие возможности, которые предоставляет PHP для работы с ассоциативными массивами. В их число входят различные механизмы перебора, получение числа элементов, оперирование ключами и значениями и т. д.

Однако здесь перечислено далеко не все, что можно делать с массивами в PHP. Язык (особенно версии 4) содержит множество других, иногда крайне полезных, функций. В этой главе мы рассмотрим большинство из них.

Сортировка массивов

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

Сортировка массива по значениям

(asort()/arsort())

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

$A=array("a"=>"Zero","b"=>"Weapon","c"=>"Alpha","d"=>"Processor"); asort($A);

foreach($A as $k=>$v) echo "$k=>$v ";

// выводит "c=>Alpha d=>Processor b=>Weapon a=>Zero" // как видим, поменялся только порядок пар ключ=>значение

Функция arsort() выполняет то же самое, за одним исключением: она упорядочивает массив не по возрастанию, а по убыванию.

Глава 13. Работа с массивами

227

Сортировка по ключам (ksort()/krsort())

Функция ksort() практически идентична функции asort(), с тем различием, что сортировка осуществляется не по значениями, а по ключам (в порядке возрастания). Например:

$A=array("d"=>"Zero", "c"=>"Weapon", "b"=>"Alpha", "a"=>"Processor"); ksort($A);

for(Reset($A); list($k,$v)=each($A);) echo "$k=>$v "; // выводит "a=>Processor b=>Alpha c=>Weapon d=>Zero"

Функция для сортировки по ключам в обратном порядке называется krsort() и применяется точно в таком же контексте, что и ksort().

Сортировка по ключам

при помощи функции uksort()

Довольно часто нам приходится сортировать что-то по более сложному критерию, чем просто по алфавиту. Например, пусть в $Files хранится список имен файлов и подкаталогов в текущем каталоге. Возможно, мы захотим вывести этот список не только в лексикографическом порядке, но также и чтобы все каталоги предшествовали файлам. В этом случае нам стоит воспользоваться функцией uksort(), написав предварительно функцию сравнения с двумя параметрами, как того требует uksort().

О функциях мы поговорим в главе 14, а пока, я надеюсь, все должно быть яс- но из примера (листинг 13.1).

Листинг 13.1. Сортировка с помощью пользовательской функции

//Эта функция должна сравнивать значения $f1 и $f2 и возвращать:

//-1, если $f1<$f2,

//0, если $f1==$f2

//1, если $f1>$f2

//Под < и > понимается следование этих имен в выводимом списке function FCmp($f1,$f2)

{ // Каталог всегда предшествует файлу if(is_dir($f1) && !is_dir($f2)) return -1;

//Файл всегда идет после каталога if(!is_dir($f1) && is_dir($f2)) return 1;

//Иначе сравниваем лексикографически

if($f1<$f2) return -1; elseif($f1>$f2) return 1; else return 0;