Пояснение к задачке «Список стран».
Итак, имеется довольно простая учебная задача, отобразить на странице список стран с флагами, кодами ISO и наименованиями на английском и русском, необходимо обеспечить сортировку по столбцам базы данных (таблицы). В качестве хранилища данных выбираем текстовый файл формата CSV
с разделителями «точка с запятой» (;
). Готовый файл можно взятьздесь или здесь. Для отображения флагов, понадобятся соответствующие картинки. Можно взять здесь или здесь
Для выбора поля, по которому сортировать данные, а также, как их сортировать (по возрастанию или убыванию), необходима форма. Добавляем код, генерирующий форму в функцию print_sortform()
, которая будет вызываться после функции print_top()
, которая, в свою очередь, печатает заголовок HTML и заголовок таблицы.
function print_sortform() { global $field; global $direction; $fields=array("ISOA2","ISOA3","ISON","EN","RU"); $sortmess=array("Aplha-2","Alpha-3","Номер","Английский","Русский"); echo "<tr><td colspan='12'><center><b>"."\n"; echo "<form name='sort' method='get' action='iso.php'> Сортировать по:"; $i=0; foreach ($fields as $f) { if ($field == $f) { echo "<nobr><input name='sort' type='radio' value='$f' checked> $sortmess[$i]</nobr> "; } else { echo "<nobr><input name='sort' type='radio' value='$f'> $sortmess[$i] </nobr>"; } $i++; } echo "<br> Направление:"; if ($direction == 0) { echo "<nobr><input name='direction' type='radio' value='0' checked> По возрастанию</nobr> "; echo "<nobr><input name='direction' type='radio' value='1'> По убыванию</nobr> "; } else { echo "<nobr><input name='direction' type='radio' value='0'> По возрастанию</nobr> "; echo "<nobr><input name='direction' type='radio' value='1' checked> По убыванию</nobr> "; } echo "<br> <input type='submit' value='Отправить'>"; echo "</form></b></center></td></tr>"; }
Ранее в скрипте объявляем две глобальных переменных
$field = "ISOA2"; //поле, по которому будем сортировать $direction = 0; //направление сортировки: 0 - по возрастанию, //иначе - по убыванию
и два массива в самой функции — $fields
и $sortmess
, содержащие идентификаторы полей и информацию для отображения их в форме. Далее в цикле foreach
формируем набор из переключателей (radiobutton) для выбора нужного поля.
Остальное в функции достаточно тривиально.
Данные будем хранить в многомерном массиве вот такой структуры:
Функция загрузки:
function load_data() { global $data; global $errmsg; $handle = fopen("isofull.csv","r"); if (!$handle) { $errmsg = "Can't open file isofull.csv"; return false; } $databuf = array(); while (!feof($handle)) { $readbuf = fgets($handle); $databuf = explode(";", $readbuf); $data[] = array ("ISOA2" => $databuf[0],"ISOA3" => $databuf[1], "ISON" => $databuf[2], "EN" => $databuf[3], "RU" => $databuf[4]); } return true; }
Заводим глобальную переменную $errmsg
для того, чтоб туда писать сообщение об ошибке, и глобальный массив $data
для нашей таблицы (БД), да, очевидный минус — я не стал париться с количеством элементов разбитой в массив строки. Но для PHP это не так, чтобы и критично. Если что просто вывалится с ошибкой. Некоторые вообще не заморачиваются обработкой ошибок в PHP, а отдают все на волю интерпретатора.
Далее, читаем построчно, разбиваем строку на составляющие и дописываем в массив ассоциативный массив с указанными полями, соответственно, в каждом элементе массива $data
будет ассоциативный массив с данными, по одному на строку. В итоге получится многомерный (вложенный) массив (в терминах PHP, в других языках «многомерный» может означать несколько другое, по мне бы так термин «вложенный» был бы лучше).
Передаем их в GET
-параметрах. Значения параметров пишем в глобальные переменные.
if (isset($_GET['sort'])) { $field=$_GET['sort']; } if (isset($_GET['direction'])) { $direction=$_GET['direction']; }
Проверять корректность переданных значений будем в функции сортировки.
В PHP имеется функция сортировки usort()
; которая принимает массив данных, в качестве первого параметра, и функцию сортировки в качестве второго. Функцию сортировки описывает пользователь. В нее передается два элемента массива, а пользователь описывает алгоритм сравнения, таким образом, чтобы пользовательская функция выдавала 3 значения: -1
: 1-й элемент < 2-го элемента
, 0
: 1-й элемент == 2-му элементу
, 1
: 1-й элемент > 2-го элемента
. Пишем соответствующую пользовательскую функцию:
function compare ($a, $b) { global $field; global $direction; global $errmsg; if (!array_key_exists($field, $a)) { $errmsg = "Field $field not found"; return 0; } if ($direction == 0) { return strnatcmp($a[$field],$b[$field]); } else { return (strnatcmp($a[$field],$b[$field])*-1); } }
1. В переменные $a
и $b
передаются два элемента массива, который надо отсортировать.
2. Далее, подключаемся к ранее заданным глобальным переменным:
— поле таблицы (БД), по которому будем сортировать.
$field
$direction
— направление сортировки — 0
по возрастанию, другое значение — по убыванию.
3. Проверяем, есть ли соответствующий ключ в массиве, а это надо проверить, т.к. ключ передается в запросе, а в запросе может придти не то, что ожидает скрипт.
if (!array_key_exists($field, $a))
...
4. Проверяем, как сортировать и сортируем с помощью функции strnatcmp()
. От стандартной strcmp()
она отличается тем, что если ей попадается набор чисел в виде строк, то она их будет сортировать в формате, обычном для человека:
strnatcmp():
4
8
10
12
16
20
24
28
strcmp():
10
100
104
108
112
116
12
120
124
strnatcpm()
(и strcpm()
), как раз возвразащают 0
, если аргументы равны, -1
если 1-й > 2-го
, и 1
, если 2-й > 1-го
.
Чтобы поменять порядок сортировки на обратный, достаточно поменять результат работы функции на обратный, что можно сделать, умножив результат функции strnatcmp()/strcmp()
на -1
:
(strnatcmp($a[$field],$b[$field])*-1)
Скриншот:
Исходник
Посмотреть, как работает
— Нет флагов некоторых редких стран (может быть потом сам нарисую).
— Почему-то страны на русскую букву Р
криво сортируются, если сортировать по русским наименованиям стран.