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

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

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

Глава 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;

228

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

}

//Пусть $Files содержит массив с ключами — именами файлов

//в текущем каталоге. Отсортируем его.

uksort($Files,"FCmp"); // передаем функцию сортировки "по ссылке"

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

Сортировка по значениям при помощи функции uasort()

Функция uasort() очень похожа на uksort(), с той разницей, что сменной (пользовательской) функции сортировки "подсовываются" не ключи, а очередные значения из массива. При этом также сохраняются связи в парах ключ=>значение.

Переворачивание массива array_reverce()

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

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

$A=array_reverse($A);

Конечно, указанная последовательность работает дольше, чем один-единственный вызов arsort().

Сортировка списка sort()/rsort()

Эти две функции предназначены в первую очередь для сортировки списков (напоминаю, что под списками я понимаю массивы, ключи которых начинаются с 0 и не имеют пропусков). Функция sort() сортирует список (разумеется, по значениям) в порядке возрастания, а rsort() — в порядке убывания. Например:

$A=array("One", "Two", "Three", "Four"); sort($A);

for($i=0; $i<count($A); $i++) echo "$i:$A[$i] "; // выводит "0:Four 1:Two 2:Three 3:One"

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

229

Любой ассоциативный массив воспринимается этими функциями как список.

То есть после упорядочивания последовательность ключей превращается в 0,1,2,..., а значения нужным образом перераспределяются. Как видим, связи между парами ключ=>значение не сохраняются, более того ключи просто пропадают, поэтому сортировать что-либо, отличное от списка, вряд ли целе- сообразно.

Сортировка списка при помощи функции usort()

Эта функция как бы является "гибридом" функций uasort() и sort(). От sort() она отличается тем, что критерий сравнения обеспечивается пользовательской функцией. А от uasort() — тем, что она не сохраняет связей между ключами и значениями, а потому пригодна разве что для сортировки списков. Вот тривиальный пример:

function FCmp($a,$b) { return strcmp($a,$b); } $A=array("One","Two","Three","Four"); usort($A);

for($i=0; $i<count($A); $i++) echo "$i:$A[$i] "; // выводит "0:Four 1:One 2:Three 3:Two"

Использованная нами функция strcmp(), как и ее пращур в Си, возвращает −1, если $a<$b, 0, если они равны, и 1, если $a>$b. В принципе, приведенный здесь пример полностью эквивалентен простому вызову sort().

Перемешивание списка shuffle()

Функция shuffle() "перемешивает" список, переданный ей первым параметром, так, чтобы его значения распределялись случайным образом. Обратите внимание, что, во-первых, изменяется сам массив, а во-вторых, ассоциативные массивы воспринимаются как списки. Пример:

$A=array(10,20,30,40,50); shuffle($A);

foreach($A as $v) echo "$v ";

Приведенный фрагмент выводит числа 10, 20, 30, 40 и 50 в случайном порядке.

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

230

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

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

Ключи и значения

array array_flip(array $Arr)

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

$A=array("a"=>"aaa", "b"=>"aaa", "c"=>"ccc"); $A=array_flip($A);

// теперь $A===array("aaa"=>"b", "ccc"=>"c");

list array_keys(array $Arr [,mixed $SearchVal])

Функция возвращает список, содержащий все ключи массива $Arr. Если задан необязательный параметр $SearchVal, то она вернет только те ключи, которым соответствуют значения $SearchVal.

Фактически, эта функция с заданным вторым параметром является обратной по отношению к оператору [] извлечению значения по его ключу.

list array_values(array $Arr)

Функция array_values() возвращает список всех значений в ассоциативном массиве $Arr. Очевидно, такое действие бесполезно для списков, но иногда оправдано для хэшей.

bool in_array(mixed $val, array $Arr)

Возвращает true, если элемент со значением $val присутствует в массиве $Arr. Впрочем, если вам часто приходится проделывать эту операцию, подумайте: не лучше ли будет воспользоваться ассоциативным массивом и хранить данные в его ключах, а не в значениях? На этом вы можете сильно выиграть в быстродействии.

array array_count_values(list $List)

Эта функция подсчитывает, сколько раз каждое значение встречается в списке $List, и возвращает ассоциативный массив с ключами — элементами списка и значениями — количеством повторов этих элементов. Иными словами, функция