You are on page 1of 83

МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ

ОДЕСЬКИЙ НАЦІОНАЛЬНИЙ МОРСЬКИЙ УНІВЕРСИТЕТ

КАФЕДРА "ТЕХНІЧНА КІБЕРНЕТИКА ім. проф. Р.В. Меркта"

ОСНОВИ PHP

Навчальний посібник

Спеціальність
122 - "Комп'ютерні науки та
інформаційні технології"

Одеса-2018
2

Навчальний посібник розроблено Бугаєвою Іриною Григорівною –


доцентом кафедри "Технічна кібернетика ім. проф. Р.В. Меркта" Одеського
національного морського університету, Новіковою Наталією Олексіївною та
Панченко Тетяною Дмитрівною - старшими викладачами тієї ж кафедри.

Посібник схвалено кафедрою ОНМУ "Технічна кібернетика ім. проф.


Р.В. Меркта" 26 січня 2018 року (протокол № 6).
3

ЗМІСТ

ВВЕДЕННЯ ....................................................................................................................................4
1 ЗМІННІ, КОНСТАНТИ, ОПЕРАТОРИ. ТИПИ ДАНИХ .......................................................7
1.1 Основи синтаксису ..............................................................................................................7
1.2 Змінні ....................................................................................................................................8
1.3 Константи ........................................................................................................................... 10
1.4 Оператори ........................................................................................................................... 11
1.5 Типи даних .........................................................................................................................12
2 КЕРУЮЧІ КОНСТРУКЦІЇ ......................................................................................................21
2.1 Умовні оператори ..............................................................................................................21
2.2 Цикли ..................................................................................................................................23
2.3 Оператори передачі керування.........................................................................................26
2.4 Оператори включення .......................................................................................................27
3 ОБРОБКА ЗАПИТІВ ЗА ДОПОМОГОЮ PHP .....................................................................28
3.1 Основи клієнт-серверних технологій ..............................................................................28
3.2 Протокол HTTP і способи передачі даних на сервер .....................................................29
3.3 Методи ................................................................................................................................ 29
3.4 Використання HTML-форм для передачі даних на сервер ...........................................30
3.7 Обробка запитів за допомогою PHP ................................................................................33
4 РОБОТА З МАСИВАМИ ДАНИХ .........................................................................................36
4.1 Операції з масивами ..........................................................................................................36
4.2 Сортування масивів ...........................................................................................................41
4.3 Виділення підмасива .........................................................................................................46
5 РОБОТА З РЯДКАМИ .............................................................................................................49
5.1 Пошук елемента в рядку ...................................................................................................49
5.2 Виділення підрядка ...........................................................................................................51
5.3 Заміна входження підрядка .............................................................................................. 54
5.4 Поділ і з'єднання рядка .....................................................................................................57
5.5 Рядки, що містять html-код ............................................................................................... 58
6 ВЗАЄМОДІЯ PHP Й MYSQL..................................................................................................60
6.1 Установка з'єднання ..........................................................................................................61
6.2 Вибір бази даних................................................................................................................62
6.3 Одержання списку полів таблиці .....................................................................................62
6.4 Відображення списку полів в html-форму ......................................................................64
6.5 Запис даних у базу даних ..................................................................................................66
6.6 Відображення даних, що зберігаються в MySQL........................................................... 68
7 АВТОРИЗАЦІЯ ДОСТУПУ ЗА ДОПОМОГОЮ СЕСІЙ .....................................................72
7.1 Авторизація доступу .........................................................................................................72
7.2 Механізм сесій ...................................................................................................................74
7.3 Настроювання сесій ...........................................................................................................75
7.4 Робота з сесіями .................................................................................................................77
ЛІТЕРАТУРА ............................................................................................................................... 83
4

ВВЕДЕННЯ

PHP - це мова сценаріїв для Web з відкритим вихідним кодом, яка


застосовується в складі серверного програмного забезпечення і призначена
для впровадження в код HTML. Система підтримки мови PHP сумісна з усіма
основними типами веб-серверів. Мова PHP дозволяє впроваджувати
фрагменти коду в звичайний код HTML-сторінок, після чого код PHP
інтерпретується в складі коду сторінок перед передачею готових сторінок
користувачам. PHP також забезпечує підключення веб-сторінок до серверних
баз даних.

Історія PHP

Мову PHP було розроблено як інструмент для рішення чисто


практичних завдань. ЇЇ творець, Расмус Лердорф, хотів знати, скільки
користувачів читають його online-резюме, і написав для цього простеньку
CGI-оболонку мовою Perl, тобто це був набір Perl-скриптів, призначених
винятково для певної мети - збору статистики відвідувань.
CGI (Common Gateway Interface - загальний інтерфейс шлюзів) є
стандартом, що призначений для створення серверних застосувань, що
працюють за протоколом HTTP. Такі застосування (їх називають шлюзами
або CGI-програмами) запускаються сервером у режимі реального часу.
Сервер передає запити користувача CGI-програмі, що їх обробляє й повертає
результат своєї роботи на екран користувача. Таким чином, відвідувач
одержує динамічну інформацію, що може змінюватися в результаті впливу
різних факторів. Сам шлюз (скрипт CGI) може бути написаний на різних
мовах програмування - C/C++, Fortran, Perl, TCL, UNIX Shell, Visual Basic,
Python й ін.
Незабаром з'ясувалося, що оболонка має невелику продуктивність, і
довелося переписати її заново, але вже мовою С. Після цього вихідні коди
були викладені на загальний огляд для виправлення помилок і доповнення.
Користувачі сервера, де розташовувався сайт з першою версією PHP,
зацікавилися інструментом, з'явилися бажаючі його використати. Так що
незабаром PHP перетворився в самостійний проект, і на початку 1995 року
вийшла перша відома версія продукту, що називалася Personal Home Page
Tools (засоби для персональної домашньої сторінки). Засоби ці були більш
ніж скромними: аналізатор коду, що розуміє лише кілька спеціальних
команд, і набір утиліт, корисних для створення гостьової книги, лічильника
відвідувань, чата й т.п.
До середини 1995 року після грунтовної переробки з'явилася друга
версія продукту, названа PHP/FI (Personal Home Page/Forms Interpreter -
персональна домашня сторінка/ інтерпретатор форм). Вона включала набір
базових можливостей сьогоднішнього PHP, можливість автоматично
5

обробляти html-форми й вбудовуватися в html-коди. Синтаксис PHP/FI


сильно нагадував синтаксис Perl, але був більш простим.
В 1997 вийшла друга версія C-реалізації PHP - PHP/FI 2.0. До того
моменту PHP використовували вже кілька тисяч чоловік по всьому світу,
приблизно з 50 тис. доменів, що становило близько 1% усього числа доменів
Internet. Офіційно PHP/FI 2.0 вийшов тільки в листопаді 1997 року,
проіснувавши до цього в основному в бета-версіях. Незабаром після виходу
його замінили альфа-версії PHP 3.0.
PHP 3.0 була першою версією, що нагадує PHP, яким ми знаємо його
сьогодні. Він дуже сильно відрізнявся від PHP/FI 2.0 і з'явився знову ж як
інструмент для рішення конкретної прикладної задачі. Його творці, Енді
Гутманс (Andi Gutmans) та Зів Сураскі (Zeev Suraski), в 1997 році переписали
заново код PHP/FI, оскільки він здався їм непридатним для розробки
застосування електронної комерції, над яким вони працювали. Для того, щоб
одержати допомогу в реалізації проекту від розроблювачів PHP/FI, Гутманс і
Сураскі вирішили об'єднатися з ними й оголосити PHP3 офіційним
спадкоємцем PHP/FI. Після об'єднання розробка PHP/FI була повністю
припинена.
Однією з сильних сторін PHP 3.0 була можливість розширення ядра.
Саме властивість розширюваності PHP 3.0 привернуло увагу безлічі
розроблювачів, що бажають додати свій модуль розширення. Крім того, PHP
3.0 надавала широкі можливості для взаємодії з базами даних, різними
протоколами й API. Немаловажним кроком до успіху виявилася розробка
нового, набагато могутнішого й повного синтаксису з підтримкою ООП. З
моменту появи PHP 3.0 змінилася не тільки функціональність і внутрішній
устрій мови, але і її назва. В абревіатурі PHP більше не було згадування про
персональне використання, PHP стало скороченням (рекурсивним
акронімом) від «PHP: Hypertext Preprocessor», що значить «PHP: препроцесор
гіпертексту».
До кінця 1998 року число користувачів PHP зросло до десятків тисяч.
Сотні тисяч web-сайтів повідомляли про те, що вони працюють з
використанням цієї мови. Майже на 10% серверів Internet був установлений
PHP 3.0.
Офіційно PHP 3.0 вийшов у червні 1998 року, після 9 місяців
публічного тестування. А вже до зими Енді Гутманс і Зів Сураскі почали
переробку ядра PHP. У їхні задачі входило збільшення продуктивності
роботи складних застосувань і поліпшення модульності коду, що лежить в
основі PHP.
Нове ядро було названо «Zend Engine» (від імен творців: Zeev й Andi) і
вперше представлено в середині 1999 року. PHP 4.0, заснований на цьому
ядрі, офіційно вийшов у травні 2000 року, майже через два роки після свого
попередника, PHP 3.0. Крім поліпшення продуктивності, PHP 4.0 мав ще
кілька ключових нововведень, таких як підтримка сесій, буферизація виводу,
6

більш безпечні способи обробки інформації, що вводиться користувачем, і


кілька нових мовних конструкцій.
Після довгої розробки й декількох пре-релізів у липні 2004 року був
випущений PHP 5. В основному він управляється ядром Zend Engine 2.0 з
новою об'єктною моделлю й безліччю різних інших нововведень.

Можливості PHP

У першу чергу PHP використовується для створення скриптів, що


працюють на стороні сервера. PHP здатний вирішувати ті ж задачі, що й
будь-які інші CGI-скрипти, у тому числі обробляти дані html-форм,
динамічно генерувати html-сторінки й т.п. Але є й інші області, де може бути
використано PHP. Усього виділяють три основні області застосування PHP.
Перша область,- це створення застосувань (скриптів), які виконуються
на стороні сервера. PHP найбільш широко використовується саме для
створення такого роду скриптів. Для того, щоб працювати таким чином,
знадобиться PHP-парсер (тобто оброблювач php-скриптів) і web-сервер для
обробки скрипта, браузер для перегляду результатів роботи скрипта, ну, і,
звичайно, який-небудь текстовий редактор для написання самого php-коду.
Друга область - це створення скриптів, що виконуються в командному
рядку. Тобто за допомогою PHP можна створювати такі скрипти, які будуть
виконуватися поза залежністю від web-сервера й браузера, на конкретній
машині. Для такої роботи буде потрібно лише парсер PHP (у цьому випадку
його називають інтерпретатором командного рядка). Цей спосіб роботи
підходить, наприклад, для скриптів, які повинні виконуватися регулярно за
допомогою різних планувальників завдань або для рішення задач простої
обробки тексту.
І остання область - це створення GUI-додатків (графічних інтерфейсів),
що виконуються на стороні клієнта. Для застосування PHP у цій області буде
потрібно спеціальний інструмент - PHP-GTK, що є розширенням PHP.
PHP підтримується майже на всіх відомих платформах, майже у всіх
операційних системах і на самих різних серверах.
За допомогою PHP можна створювати зображення, PDF-файли, флеш-
ролики, у нього включена підтримка великої кількості сучасних баз даних,
вбудовані функції для роботи з текстовими даними будь-яких форматів,
включаючи XML, і функції для роботи з файловою системою. PHP підтримує
взаємодію з різними сервісами за допомогою відповідних протоколів, таких
як протокол керування доступом до директорій LDAP, протокол роботи з
мережним устаткуванням SNMP, протоколи передачі повідомлень IMAP,
NNTP й POP3, протокол передачі гіпертексту HTTP і т.д.
7

1 ЗМІННІ, КОНСТАНТИ, ОПЕРАТОРИ. ТИПИ ДАНИХ

Важливим елементом кожної мови є змінні, константи й оператори, що


застосовуються до цих змінних й констант.

1.1 Основи синтаксису

Об'єднання з HTML

Перше, що необхідно знати щодо синтаксису PHP, - це те, як він


вбудовується в HTML-код, як інтерпретатор довідається, що це код мовою
PHP.
Коли інтерпретатор PHP аналізує код сторінки, він ігнорує текст файлу
доти, поки не зустріне один зі спеціальних тегів, які вказують наступні за
ними інструкції сприймати як PHP-код. Ці інструкції він буде виконувати
доти, поки не зустрінеться закриваючий тег, що сигналізує про завершення
інструкцій PHP. Цей механізм дозволяє впроваджувати PHP-код в HTML: усе
за межами тегів PHP залишається без змін, а усередині тегів - розбирається як
код.
Існує чотири способи позначити блок PHP команд. Але тільки два
(<?php ?> й <script language="php"></script>) можуть
застосовуватися завжди; два інших можуть заборонятися у файлі
настроювань php.ini.
Ось список способів, як можна вмонтувати PHP-код в HTML-
документ:
1)
<?php
echo("Для XHTML й XML документів використайте цю
форму\n");
?>

2)
<?
echo ("Це найпростіший спосіб\n");
?>

або

<?= вираження ?>

скорочення від "<? Echo вираження ?>"

3)
<script language="php">
8

echo ("Ще одна форма введення");


</script>

4)
<%
echo ("Можна використати теги в стилі ASP");
%>

Спосіб номер 1 самий кращий, тому що він буде працювати в будь-


яких інтерпретаторах.
Способом номер 2 не завжди можна скористатися, тому що він працює
тільки якщо значення параметра short_open_tag у файлі php.ini
дорівнює on або інтерпретатор скомпільований з командою --enable-
short-tags. Однак, навіть якщо ця форма й дозволена, її використання
небажано.
Спосіб номер 4 буде працювати, якщо значення змінної настроювань
asp_tags дорівнює on. Підтримка asp тегів з'явилася в PHP 3.0.4.
Примітка: використання скорочених тегів повинне бути виключене при
розробці застосувань або бібліотек, призначених для поширення або при
публікації на PHP-сервери, які вами не контролюються, оскільки скорочені
теги можуть не підтримуватися на цільовому сервері. Для забезпечення
переносимості й поширення коду не використовуйте скорочені теги.
У прикладах ми будемо використовувати варіант <?php ?>.

Розділення інструкцій

Програма на PHP (та й на будь-якій іншій мові програмування) - це


набір команд (інструкцій). Оброблювачеві програми (парсеру) необхідно
якось відрізняти одну команду від іншої. Для цього використовуються
спеціальні символи - роздільники. В PHP інструкції розділяються крапкою з
комою.
Закриваючий тег «?>» також має на увазі кінець інструкції, тому перед
ним крапку з комою не ставлять.

Коментарі

PHP підтримує кілька видів коментарів: у стилі C, C++ й оболонки


Unix. Символи // й # позначають початок однорядкових коментарів, /* й */ -
відповідно початок і кінець багаторядкових коментарів.

1.2 Змінні

Змінна в PHP позначається знаком долара, за яким слідує її ім'я.


Наприклад:
9

$my_var

Ім'я змінної чутливе до регістра, тобто змінні $my_var й $My_var


різні.
Імена змінних відповідають тим же правилам, що й інші найменування
в PHP: правильне ім'я змінної повинне починатися з букви або символу
підкреслення з наступними в будь-якій кількості буквами, цифрами або
символами підкреслення.
В PHP 3 змінні завжди присвоювалися за значенням. Тобто коли ви
присвоюєте вираз змінній, всі значення оригінального виразу копіюються в
цю змінну. Це означає, наприклад, що після присвоєння одній змінній
значення іншої, зміна однієї з них не впливає на значення іншої.

<?php
$first = ' Text '; // Привласнюємо $first
значення ' Text '
$second = $first; // Привласнюємо $second
значення змінної $first
$first = ' New text '; // Змінюємо значення $first
на ' New text '
echo "Змінна з ім'ям first ".
"дорівнює $first <br>"; // Виводимо значення
$first
echo "Змінна з ім'ям second ".
"дорівнює $second"; // Виводимо значення
$second
?>

Результат роботи цього скрипта буде наступним:

Змінна з ім'ям first дорівнює New text


Змінна з ім'ям second дорівнює Text

PHP 4, крім цього, пропонує ще один спосіб присвоєння значень


змінним: присвоєння по посиланню. Для того, щоб присвоїти значення
змінної по посиланню, це значення повинне мати ім'я, тобто воно повинне
бути представлене якою-небудь змінною. Щоб указати, що значення одної
змінної присвоюється іншій змінній по посиланню, потрібно перед ім'ям
першої змінної поставити знак амперсанд &.
Розглянемо той же приклад, що й вище, тільки будемо присвоювати
значення змінної $first змінній $second по посиланню:

<?php
$first = ' Text '; // Присвоюємо $first значення '
Text '
10

$second = &$first; /* Робимо посилання на $first через


$second.
Тепер значення цих змінних будуть
завжди співпадати */
$first = ' New text '; // Змінимо значення $first на '
New text '
// Виведемо значення обох змінних

echo "Змінна з ім'ям first дорівнює $first <br>";


echo "Змінна з ім'ям second дорівнює $second";
?>

Цей скрипт виведе наступне:

Змінна з ім'ям first дорівнює New text


Змінна з ім'ям second дорівнює New text

Тобто разом зі змінною $first змінилася й змінна $second.

1.3 Константи

Для зберігання постійних величин, тобто таких величин, значення яких


не міняється в ході виконання скрипта, використовуються константи. Такими
величинами можуть бути математичні константи, паролі, шляхи до файлів і
т.п. Основна відмінність константи від змінної полягає в тому, що їй не
можна присвоїти значення більше одного разу і її значення не можна
анулювати після її оголошення. Крім того, у константи немає приставки у
вигляді знака долара і її не можна визначити простим присвоюванням
значення. Як же тоді можна визначити константу? Для цього існує
спеціальна функція define(). Її синтаксис такий:

define("Ім'я_константи",
"Значення_константи",
[Нечутливість_до_регістра])

За замовчуванням імена констант чутливі до регістра. Для кожної


константи це можна змінити, указавши як значення аргументу
Нечутливість_до_регістра значення True. Існує угода, по якому
імена констант завжди пишуться у верхньому регістрі.
Отримати значення константи можна, указавши її ім'я. На відміну від
змінних, не потрібно випереджати ім'я константи символом $. Крім того, для
одержання значення константи можна використати функцію constant() з
ім'ям константи в якості параметра.
11

<?php
// визначаємо константу PASSWORD
define("PASSWORD","qwerty");
// визначаємо регістронезалежну
// константу PI зі значенням 3.14
define("PI","3.14", True);
// виведемо значення константи PASSWORD, тобто qwerty
echo (PASSWORD);
// теж виведе qwerty
echo constant("PASSWORD");
echo (password);
/* виведе password, оскільки ми ввели регістрозалежну
константу PASSWORD */
echo pi;
// виведе 3.14, оскільки константа PI
// регістронезалежна по визначенню
?>

Крім змінних, які декларуються користувачем, в PHP існує ряд


констант, визначених самим інтерпретатором. Наприклад, константа
__FILE__ зберігає ім'я файлу програми (і шлях до нього), що виконується в
цей момент, __FUNCTION__ містить ім'я функції, __CLASS__ – ім'я класу,
PHP_VERSION – версія інтерпретатора PHP.

1.4 Оператори

Оператори дозволяють виконувати різні дії зі змінними, константами й


виразами. Вираз можна визначити як усе, що завгодно, що має значення.
Змінні й константи - це основні й найбільш прості форми виразів. Існує
безліч операцій (і відповідних їм операторів), які можна робити з виразами.
Розглянемо деякі з них докладніше.

Арифметичні оператори

+ Додавання
- Віднімання
* Множення
/ Ділення
% Залишок від ділення

Строкові оператори

. Конкатенація (додавання рядків)


12

Оператори присвоювання

= Присвоювання. Змінній ліворуч від оператора буде присвоєне


значення, отримане в результаті виконання яких-небудь операцій, або
змінної/константи з правої сторони.
+= Додає до змінної число й потім присвоює їй отримане значення.
.= Скорочено позначає комбінацію операцій конкатенації й
присвоювання (спочатку додається рядок, потім отриманий рядок
записується в змінну).

Логічні оператори

and І
&& І
or Або
|| Або
xor Виключаюче або (Оператор повертає значення true, якщо один і
тільки один з операндів має значення true. Якщо обоє операнда мають
значення true, оператор поверне значення false.)
! Заперечення (Інверсія NOT)

Оператори порівняння

== Рівність. Значення змінних рівні.


=== Еквівалентність. Рівні значення й типи змінних.
!= Нерівність. Значення змінних не рівні.
<> Нерівність. Значення змінних не рівні.
!== Нееквівалентність. Змінні не еквівалентні.
< Менше.
> Більше.
<= Менше або дорівнює.
>= Більше або дорівнює.

Оператори інкремента й декремента

++$a Збільшує $a на одиницю й повертає $a.


$a++ Повертає $a, потім збільшує $a на одиницю.
--$a Зменшує $a на одиницю й повертає $a.
$a-- Повертає $a, потім зменшує $a на одиницю.

1.5 Типи даних

PHP підтримує вісім простих типів даних.


Чотири скалярних типи:
13

 boolean (логічний);
 integer (цілий);
 float (з плаваючою крапкою);
 string (строковий).
Два змішаних типи:
 array (масив);
 object (об'єкт).
І два спеціальних типи:
 resource (ресурс);
 NULL.
В PHP не прийняте явне оголошення типів змінних. Переважніше, щоб
це робив сам інтерпретатор під час виконання програми залежно від
контексту, у якому використовується змінна. Розглянемо по порядку всі
перераховані типи даних.

Тип boolean (логічний тип)

Цей найпростіший тип виражає істинність значення, тобто змінна цього


типу може мати тільки два значення - істина TRUE або неправда FALSE.
Щоб визначити логічний тип, використовують ключове слово TRUE
або FALSE. Обоє регістронезалежні.

<?php
$test = True;
?>

Логічні змінні використовуються в різних керуючих конструкціях


(циклах, умовах і т.п.). Мати логічний тип, тобто приймати тільки два
значення, істину або неправду, можуть також і деякі оператори (наприклад,
оператор рівності). Вони також використовуються в керуючих конструкціях
для перевірки яких-небудь умов. Наприклад, в умовній конструкції
перевіряється істинність значення оператора або змінної й залежно від
результату перевірки виконуються ті або інші дії. Тут умова може бути
істинною або хибною, що саме й відображає змінна й оператор логічного
типу.

<?php
if ($test == False) {
echo "Вивчай PHP!";
}
?>
14

Тип integer (цілі)

Цей тип задає число з множини цілих чисел Z = {..., -2, -1, 0, 1, 2, ...}.
Цілі можуть бути зазначені в десятковій, шестнадцатеричній або
восьмеричній системі числення, за бажанням з попереднім знаком «-» або
«+».
Якщо ви використовуєте восьмеричну систему числення, ви повинні
випередити число 0 (нулем), для використання шестнадцатеричної системи
потрібно поставити перед числом 0x.

<?php
# десяткове число
$a = 1234;
# негативне число
$a = -123;
# восьмеричне число (еквівалентно 83 у десятковій
системі)
$a = 0123;
# шестнадцатеричне число (еквівалентно 26 у десятковій
системі)
$a = 0x1A;
?>

Розмір цілого залежить від платформи, хоча, як правило, максимальне


значення біля двох мільярдів (це 32-бітне знакове). Беззнакові цілі PHP не
підтримує.
Якщо ви визначите число, що перевищує межі цілого типу, воно буде
інтерпретоване як число з плаваючою крапкою. Також якщо ви використаєте
оператор, результатом роботи якого буде число, що перевищує межі цілого,
замість нього буде повернуте число з плаваючою крапкою.
В PHP не існує оператора ділення цілих. Результатом 1/2 буде число з
плаваючою крапкою 0.5. Ви можете привести значення до цілого, що завжди
округляє його в меншу сторону, або використати функцію round(), що
округляє значення за стандартними правилами. Для перетворення змінної до
конкретного типу потрібно перед змінною вказати в дужках потрібний тип.
Наприклад, для перетворення змінної $a=0.5 до цілого типу необхідно
написати (integer)(0.5) або (integer)$a або використати
скорочений запис (int)(0.5). Можливість явного приведення типів за
таким принципом існує для всіх типів даних (звичайно, не завжди значення
одного типу можна перевести в інший тип). Ми не будемо заглиблюватися в
усі тонкості приведення типів, оскільки PHP робить це автоматично залежно
від контексту.
15

Тип float (числа з плаваючою крапкою)

Числа з плаваючою крапкою (вони ж числа подвійної точності або


дійсні числа) можуть бути визначені за допомогою кожного з наступних
синтаксисів:

<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
?>

Розмір числа з плаваючою крапкою залежить від платформи, хоча


максимум, як правило, ~1.8e308 з точністю близько 14 десяткових цифр.

Тип string (рядок)

Рядок - це набір символів. В PHP символ - це теж саме, що байт, це


значить, що існує рівно 256 різних символів. Це також означає, що PHP не
має вбудованої підтримки Unicode. В PHP практично не існує обмежень на
розмір рядків, тому немає абсолютно ніяких причин турбуватися про їхню
довжину.
Рядок в PHP може бути визначений різними способами:
 за допомогою одинарних лапок;
 за допомогою подвійних лапок.

Одинарні лапки

Найпростіший спосіб визначити рядок - це укласти його в одинарні


лапки «'». Щоб використати одинарні лапки усередині рядка, як й у багатьох
інших мовах, перед ними необхідно поставити символ зворотної косої риси
«\», тобто екранувати їх. Якщо зворотна коса риса повинна йти перед
одинарними лапками або бути наприкінці рядка, необхідно продублювати її
«\\'».
Якщо усередині рядка, укладеного в одинарні лапки, зворотний слеш
«\» зустрічається перед будь-яким іншим символом (відмінним від «\» й «'» ),
то він розглядається як звичайний символ і виводиться, як і всі інші. Тому
зворотну косу рису необхідно екранувати, тільки якщо вона перебуває
наприкінці рядка, перед закриваючими лапками.
В PHP існує ряд комбінацій символів, що починаються з символу
зворотної косої риси. Їх називають керуючими послідовностями, і вони
мають спеціальні значення. Отож, на відміну від двох інших синтаксисів,
змінні й керуючі послідовності для спеціальних символів, що зустрічаються в
рядках, укладених в одинарні лапки, не обробляються.
16

<?php
echo 'Також ви можете вставляти в рядки
символ нового рядка';
// Виведе: Щоб вивести ' треба перед нею поставити \
echo 'Щоб вивести \' треба перед '.
'нею поставити \\';
// Виведе: Ви хочете видалити C:\*.*?
echo 'Ви хочете видалити C:\\*.*?';
// Виведе: Це не вставить: \n новий рядок
echo 'Це не вставить: \n новий рядок';
// Виведе: Значення змінних $expand й $either не
підставляються
echo 'Значення змінних $expand й $either'.
' не підставляються';
?>

Подвійні лапки

Якщо рядок укладений у подвійні лапки «"», PHP розпізнає більшу


кількість керуючих послідовностей для спеціальних символів. Деякі з них
наведені нижче.

Керуючі послідовності

\n Новий рядок (LF або 0x0A (10) в ASCII)


\r Повернення каретки (CR або 0x0D (13) в ASCII)
\t Горизонтальна табуляція (HT або 0x09 (9) в ASCII)
\\ Зворотна коса риса
\$ Знак долара
\" Подвійні лапки

Якщо ви захочете екранувати будь-який інший символ, зворотна коса


риса також буде надрукована!
Найважливішою властивістю рядків у подвійних лапках є обробка
змінних.

Тип array (масив)

Масив в PHP являє собою впорядковану карту - тип, що перетворює


значення в ключі. Цей тип оптимізований у декількох напрямках, тому ви
можете використовувати його як властиво масив, список (вектор), хеш-
таблицю (яка є реалізацією карти), стек, чергу й т.д. Оскільки ви можете мати
в якості значення інший масив PHP, можна також легко емулювати дерева.
17

Визначити масив можна за допомогою конструкції array() або


безпосередньо задаючи значення його елементам.
Визначення за допомогою array()

array ([key] => value,[key1] => value1, ... )

Мовна конструкція array() приймає в якості параметрів пари ключ


=> значення, розділені комами. Символ => установлює відповідність між
значенням і його ключем. Ключ може бути як цілим числом, так і рядком, а
значення може бути будь-якого наявного в PHP типу. Числовий ключ масиву
часто називають індексом. Індексування масиву в PHP починається з нуля.
Значення елемента масиву можна одержати, указавши після імені масиву у
квадратних дужках ключ шуканого елемента. Запис $a["1"] рівносильний
запису $a[1], так само як й $a["-1"] рівносильне $a[-1].

<?php
$books = array ("php" =>"PHP users guide",
12 => true);
echo $books["php"]; //виведе "PHP users guide"
echo $books[12];
?>

Якщо для елемента ключ не заданий, то в якості ключа береться


максимальний числовий ключ, збільшений на одиницю. Якщо вказати ключ,
якому вже було присвоєне якесь значення, то воно буде перезаписано.
Починаючи з PHP 4.3.0, якщо максимальний ключ - негативне число, то
наступним ключем масиву буде нуль (0).

<?php
// масиви $arr й $arr1 еквівалентні
$arr = array(5 => 43, 32, 56, "b" => 12);
$arr1 = array(5 => 43, 6 => 32,
7 => 56, "b" => 12);
?>

Якщо використати як ключ TRUE або FALSE, то його значення


переводиться відповідно в одиницю й нуль типу integer. Якщо використати
NULL, то замість ключа одержимо порожній рядок. Можна використати й
сам порожній рядок як ключ, при цьому його треба брати в лапки. Так що це
не те ж саме, що використання порожніх квадратних дужок. Не можна
використати як ключ масиви й об'єкти.

Визначення за допомогою синтаксису квадратних дужок


18

Створити масив можна, просто записуючи в нього значення. Значення


елемента масиву можна одержати за допомогою квадратних дужок,
усередині яких потрібно вказати його ключ, наприклад, $book["php"]. Якщо
вказати новий ключ і нове значення, наприклад,
$book["new_key"]="new_value", то в масив додасться новий елемент. Якщо
ми не вкажемо ключ, а тільки присвоїмо значення $book[]="new_value", то
новий елемент масиву буде мати числовий ключ, на одиницю більший
максимального існуючого. Якщо масив, у який ми додаємо значення, ще не
існує, то він буде створений.

<?php
$books["key"]= value; // додали в масив $books значення
// value з ключем key
$books[] = value1; /* додали в масив значення value1 з
ключем 13, оскільки максимальний
ключ був 12 */
?>

Для того щоб змінити конкретний елемент масиву, потрібно просто


присвоїти йому з його ключем нове значення. Змінити ключ елемента не
можна, можна тільки видалити елемент (пару ключ/значення) і додати новий.
Щоб видалити елемент масиву, потрібно використати функцію unset().

<?php
$books = array ("php" =>"PHP users guide",
12 => true);

$books[] = "Book about Perl"; // додали елемент з


ключем (індексом) 13
// це еквівалентно $books[13]
= "Book about Perl";
$books["lisp"] = 123456; /* Це додає до масиву новий
елемент з ключем "lisp" і
значенням 123456 */
unset($books[12]); // Це видаляє елемент з ключем
12 з масиву
unset ($books); // видаляє масив повністю
?>

Помітимо, що, коли використовуються порожні квадратні дужки,


максимальний числовий ключ шукається серед ключів, що існують у масиві з
моменту останнього переіндексування. Переіндексувати масив можна за
допомогою функції array_values().

<?php
19

$arr = array ("a","b","c"); /* Створюємо масив зі


значеннями
"a", "b" й "c". Оскільки
ключі
не зазначені, вони
будуть 0,1,2
відповідно */
print_r($arr); // виводимо масив (і ключі,і
значення)
unset($arr[0]);
unset($arr[1]);
unset($arr[2]);
// видаляємо з нього всі
значення
print_r($arr); // виводимо масив (і ключі,
і значення)
$arr[] = "aa"; // додаємо новий елемент у
масив.
// Його індексом
(ключем)буде 3, а не 0
print_r($arr);

$arr = array_values($arr); // переіндексуємо масив


$arr[] = "bb"; // ключем цього елемента
буде 1
print_r($arr);
?>

Результатом роботи цього скрипта буде:

Array ( [0] => a [1] => b [2] => c )


Array ( )
Array ( [3] => aa )
Array ( [0] => aa [1] => bb )

Тип object (об'єкти)

Об'єкти - тип даних, що прийшов з об’єктно-орієнтованого


програмування (ООП). Відповідно до принципів ООП, клас - це набір
об'єктів, що володіють певними властивостями й методами роботи з ним, а
об'єкт відповідно - екземпляр класу.
В PHP для доступу до методів об'єкта використовується оператор ->.
Для ініціалізації об'єкта використовується вираз new, що створює в змінній
екземпляр об'єкта.
20

<?php
//створюємо клас людей
class Person
{
// метод, що навчає людину PHP
function know_php()
{
echo "Тепер я знаю PHP";
}
}
$bob = new Person; // створюємо об'єкт класу людина
$bob -> know_php(); // навчаємо його PHP
?>

Тип resource (ресурси)

Ресурс - це спеціальна змінна, що містить посилання на зовнішній


ресурс (наприклад, з'єднання з базою даних). Ресурси створюються й
використовуються спеціальними функціями (наприклад,
mysql_connect(), pdf_new() і т.п.).

Тип Null

Спеціальне значення NULL говорить про те, що змінна не має


значення.
Змінна вважається NULL, якщо:
 їй була присвоєна константа NULL ($var = NULL);
 їй ще не було присвоєне яке-небудь значення;
 вона була вилучена за допомогою unset().
Існує тільки одне значення типу NULL - регістронезалежне ключове
слово NULL.
21

2 КЕРУЮЧІ КОНСТРУКЦІЇ

Розглядаються умовні оператори (if, switch), робота з циклами


(while, for, foreach) і використання функцій include, require.

2.1 Умовні оператори

Оператор if

Оператор if дозволяє виконувати фрагменти коду залежно від умови.


Структуру оператора if можна представити в такий спосіб:

if (вираз) блок_виконання

Тут вираз є будь-який правильний PHP-вираз (тобто все, що має


значення). У процесі обробки скрипта вираз перетвориться до логічного
типу. Якщо в результаті перетворення значення виразу істинно (True), то
виконується блок_виконання. У противному випадку блок_виконання
ігнорується. Якщо блок_виконання містить кілька команд, то він повинен
бути укладений у фігурні дужки { }.

Правила перетворення виразу до логічного типу

В FALSE перетворяться наступні значення:


 логічне False;
 цілий нуль (0);
 дійсний нуль (0.0);
 порожній рядок і рядок "0";
 масив без елементів;
 об'єкт без змінних;
 спеціальний тип NULL.
Всі інші значення перетворяться в TRUE.

Оператор else

Ми розглянули тільки одну, основну частину оператора if. Існує


кілька розширень цього оператора. Оператор else розширює if на
випадок, якщо вираз, що перевіряється в if, є невірним, і дозволяє виконати
які-небудь дії за таких умов.
Структуру оператора if, розширеного за допомогою оператора else,
можна представити в такий спосіб:

if (вираз) блок_виконання else блок_виконання1


22

Цю конструкцію if...else можна інтерпретувати приблизно так:


якщо виконано умову (тобто вираз=true), то виконуємо дії з
блоку_виконання, інакше - дії з блоку_виконання1. Використовувати
оператор else не обов'язково.

Оператор elseif

Ще один спосіб розширення умовного оператора if - використання


оператора elseif. elseif - це комбінація else й if. Як й else, він
розширює if для виконання різних дій у тому випадку, якщо умова, що
перевіряється в if, невірна. Але на відміну від else, альтернативні дії
будуть виконані, тільки якщо elseif-умова є вірною. Структуру оператора
if, розширеного за допомогою операторів else й elseif, можна
представити в такий спосіб:

if (вираз) блок_виконання
elseif(вираз1) блок_виконання1
...
else блок_ виконанняN

Операторів elseif може бути відразу кілька в одному if-блоці.


Elseif-твердження буде виконано, тільки якщо попередня if-умова є
False, всі попередні elseif-умови є False, а дана elseif-умова - True.

Оператор switch

Ще одна конструкція, що дозволяє перевіряти умову й виконувати


залежно від цього різні дії, - це switch. На українську мову назву даного
оператора можна перевести як «перемикач». І зміст у нього саме такий.
Залежно від того, яке значення має змінна, він перемикається між різними
блоками дії. Оператор switch дуже схожий на оператор
if...elseif...else або набір операторів if. Структуру switch можна
записати в такий спосіб:

switch (вираз або змінна){


case значення1:
блок_дій1
break;
case значення2:
блок_дій2
break;
...
default:
23

блок_дій_за_замовчуванням}

На відміну від if, тут значення виразу не приводиться до логічного


типу, а просто порівнюється зі значеннями, перерахованими після ключових
слів case (значення1, значення2 і т.д.). Якщо значення виразу збіглося
з якимсь варіантом, то виконується відповідний блок_дій - від двокрапки
після значення, що збіглося, до кінця switch або до першого оператора
break, якщо такий знайдеться. Якщо значення виразу не збіглося з жодним з
варіантів, то виконуються дії за замовчуванням (блок_дій_
за_замовчуванням), що знаходяться після ключового слова default.
Вираз в switch обчислюється тільки один раз, а в операторі elseif -
щораз, тому, якщо вираз досить складний, то switch працює швидше.

Приклад. Вивести на екран повідомлення.

<?php
$names = array("Іван","Петро","Семен");
switch ($names[0]){
case "Іван":
echo "Привіт, Іван!";
break;
case "Петро":
echo "Привіт, Петро!";
break;
case "Семен":
echo "Привіт, Семен!";
break;
default:
echo "Привіт, $names[0]!";
}
?>

Якщо в цьому прикладі опустити оператор break, наприклад, в case


"Петро":, то, якщо змінна виявиться рівною рядку "Петро", після виводу на
екран повідомлення "Привіт, Петро!" програма піде далі й виведе також
повідомлення "Привіт, Семен!" і тільки потім, зустрівши break, продовжить
своє виконання за межами switch.

2.2 Цикли

В PHP існує кілька конструкцій, що дозволяють виконувати


повторювані дії залежно від умови. Це цикли while, do..while, foreach
й for. Розглянемо їх більш докладно.
24

while

Структура оператора:

while (вираз) {блок_виконання}

while - простий цикл. Він пропонує PHP виконувати команди


блоку_виконання доти, поки вираз обчислюється як True (тут, як й в if,
відбувається приведення виразу до логічного типу). Значення виразу
перевіряється щораз на початку циклу, так що, навіть якщо його значення
змінилося в процесі виконання блоку_виконання, цикл не буде зупинений
до кінця ітерації (тобто поки всі команди блоку_виконання не будуть
виконані).

Приклад. Надрукувати всі парні цифри.

<?php
$i = 1;
while ($i < 10) {
if ($i % 2 == 0) print $i;
// друкуємо цифру, якщо вона парна
$i++;
// збільшуємо $i на одиницю
}
?>

do... while

Цикли do..while дуже схожі на цикли while, з тією лише різницею,


що істинність виразу перевіряється наприкінці циклу, а не на початку.
Завдяки цьому блок_виконання циклу do...while гарантовано
виконується хоча б один раз.
Структура оператора:

do {блок_виконання} while (вираз);

Приклад. Надрукувати всі парні цифри.

<?php
// ця програма надрукує число 12, незважаючи на те,
// що умова циклу не виконана
$i = 12;
do{
if ($i % 2 == 0) print $i;
25

// якщо число парне, то друкуємо його


$i++;
// збільшуємо число на одиницю
}while ($i<10)
?>

for

Структура оператора:

for (вираз1; вираз2; вираз3) {блок_виконання}

Тут умова складається відразу з трьох виразів. Перший вираз вираз1


обчислюється безумовно один раз на початку циклу. На початку кожної
ітерації обчислюється вираз2. Якщо результат обчислення є True, то цикл
триває й виконуються всі команди блоку_виконання. Якщо вираз2
обчислюється як False, то виконання циклу зупиняється. Наприкінці
кожної ітерації (тобто після виконання всіх команд блоку_виконання)
обчислюється вираз3.
Наприклад, всі парні цифри можна вивести з використанням циклу for
у такий спосіб:

<?php
for ($i=0; $i<10; $i++){
if ($i % 2 == 0) print $i;
// друкуємо парні числа
}
?>

У третій вираз конструкції for можна записувати через кому відразу


кілька найпростіших команд. Наприклад, якщо ми хочемо просто вивести всі
цифри, то програму можна записати зовсім просто:

<?php
for ($i=0; $i<10; print $i, $i++)
/* Якщо блок_виконання не містить команд
або містить тільки одну команду,
фігурні дужки, у які він укладений,
можна опускати */
?>

foreach
26

Ще одна корисна конструкція. Вона з'явилася тільки в PHP4 і


призначена винятково для роботи з масивами.
Синтаксис:
foreach ($array as $value)
{блок_виконання}

або

foreach ($array as $key => $value)


{блок_виконання}

У першому випадку формується цикл по всіх елементах масиву,


заданого змінною $array. На кожному кроці циклу значення поточного
елемента масиву записується в змінну $value, і внутрішній лічильник
масиву пересувається на одиницю (так що на наступному кроці буде видний
наступний елемент масиву). Усередині блоку_виконання значення
поточного елемента масиву може бути отримане за допомогою змінної
$value. Виконання блоку_виконання відбувається стільки разів, скільки
елементів у масиві $array.
Друга форма запису на додаток до перерахованого вище на кожному
кроці циклу записує ключ поточного елемента масиву в змінну $key, що теж
можна використати в блоці_виконання.
Коли foreach починає виконання, внутрішній покажчик масиву
автоматично встановлюється на перший елемент.

Приклад. Вивести всім вітання та їхні номери в списку.

<?php
$names = array("Іван","Петро","Семен");
foreach ($names as $val) {
echo "Привіт, $val <br>";
// виведе всім вітання
}
foreach ($names as $k => $val) {
//крім вітання, виведемо номери в списку, тобто ключі
echo "Привіт, $val!
Ти в списку під номером $k <br>";
}
?>

2.3 Оператори передачі керування

Іноді потрібно негайно завершити роботу циклу або окремої його


ітерації. Для цього використовують оператори break й continue.
27

Оператор break закінчує виконання поточного циклу, будь то for,


foreach, while, do..while або switch.
Іноді потрібно не повністю припинити роботу циклу, а тільки почати
його нову ітерацію. Оператор continue дозволяє пропустити подальші
інструкції з блоку_виконання будь-якого циклу й продовжити виконання
з нового кола.

2.4 Оператори включення

Оператор include дозволяє включати код, що міститься в


зазначеному файлі, і виконувати його стільки разів, скільки програма
зустрічає цей оператор. Включення може здійснюватись кожним з
перерахованих способів:

include 'ім'я_файлу';
include $file_name;
include ("ім'я_файлу");

Оператор require також дозволяє включати в програму й виконувати


який-небудь файл. Основна відмінність require й include полягає в
тому, як вони реагують на виникнення помилки. Оператор include видає
попередження, і робота скрипта триває. Помилка в require викликає
фатальну помилку роботи скрипта й припиняє його виконання.
28

3 ОБРОБКА ЗАПИТІВ ЗА ДОПОМОГОЮ PHP

Розділ присвячений вивченню способів відправлення даних на сервер й


їхній обробці за допомогою PHP. Розглядаються основні поняття клієнт-
серверних технологій. Розглядається поняття HTML-форми й відправлення
даних з її допомогою. Дається коротка характеристика методів Post й Get.
Розглядається механізм одержання даних з HTML-форм й їхня обробка за
допомогою PHP. Наведено приклад - створення форми для реєстрації
користувачів на сайті, відправлення «універсального листа» всім, що
зареєструвалися.

3.1 Основи клієнт-серверних технологій

PHP - це скриптова мова, що обробляється сервером.


Сервер являє собою набір програм, які контролюють виконання різних
процесів. Відповідно, цей набір програм установлений на якомусь
комп'ютері. Часто комп'ютер, на якому встановлений сервер, і називають
сервером. Основна функція комп'ютера-сервера - по запиті клієнта запустити
який-небудь певний процес і відправити клієнтові результати його роботи.
Клієнтом називають будь-який процес, що користується послугами
сервера. Клієнтом може бути як користувач, так і програма. Основне
завдання клієнта - виконання додатка й здійснення зв'язку з сервером, коли
цього вимагає додаток. Тобто клієнт повинен надавати користувачеві
інтерфейс для роботи з додатком, реалізовувати логіку його роботи й при
необхідності відправляти завдання серверу.
Взаємодія між клієнтом і сервером починається з ініціативи клієнта.
Клієнт запитує вид обслуговування, установлює сеанс, одержує потрібні
йому результати й повідомляє про закінчення роботи.
Послугами одного сервера найчастіше користується кілька клієнтів
одночасно. Тому кожен сервер повинен мати досить велику продуктивність і
забезпечувати безпеку даних.
Логічніше всього встановлювати сервер на комп'ютері, що входить у
яку-небудь мережу, локальну або глобальну. Однак можна встановлювати
сервер і на окремий комп'ютер (тоді він буде одночасно й клієнтом і
сервером).
З усіх типів серверів нас в основному цікавить сервер WWW. Часто
його називають web-сервером, http-сервером або навіть просто сервером. Що
являє собою web-сервер? По-перше, це сховище інформаційних ресурсів. По-
друге, ці ресурси зберігаються й надаються користувачам у відповідності зі
стандартами Internet (такими, як протокол передачі даних HTTP). Робота з
документами web-сервера здійснюється за допомогою браузера (наприклад,
IE, Opera або Chrome), що відсилає серверу запити, створені відповідно до
протоколу HTTP. У процесі виконання завдання сервер може зв'язуватися з
іншими серверами.
29

Як приклади web-серверів можна привести сервер Apache групи


Apache, Internet Information Server (IIS) компанії Microsoft, SunOne фірми Sun
Microsystems, WebLogic фірми BEA Systems, IAS (Inprise Application Server)
фірми Borland, WebSphere фірми IBM, OAS (Oracle Application Server).

3.2 Протокол HTTP і способи передачі даних на сервер

HTTP надає набір методів для вказівки цілей запиту, що відправляє


серверу. Ці методи засновані на дисципліні посилань, де для вказівки
ресурсу, до якого повинен бути застосований даний метод, використовується
універсальний ідентифікатор ресурсів (Universal Resource Identifier) у вигляді
місцезнаходження ресурсу (Universal Resource Locator, URL) або у вигляді
його універсального імені (Universal Resource Name, URN).
Протокол реалізує принцип запит/відповідь. Запитуюча програма-
клієнт ініціює взаємодію з програмою-сервером, що відповідає, і надсилає
запит, що містить:
 метод доступу;
 адресу URI;
 версію протоколу;
 повідомлення (схоже за формою на MIME) з інформацією про
тип переданих даних, інформацією про клієнта, що послав запит,
і, можливо, зі змістовною частиною (тілом) повідомлення.
Відповідь сервера містить:
 рядок стану, у який входить версія протоколу й код повернення
(успіх або помилка);
 повідомлення (у формі, схожій на MIME), у яке входить
інформація сервера, метаінформація (тобто інформація про зміст
повідомлення) і тіло повідомлення.
У протоколі не вказується, хто повинен відкривати й закривати
з'єднання між клієнтом і сервером. На практиці з'єднання, як правило,
відкриває клієнт, а сервер після відправлення відповіді ініціює його розрив.
Далі ми розглянемо найпоширеніші методи відправлення запитів.

3.3 Методи

Як уже говорилося, будь-який запит клієнта до сервера повинен


починатися з вказівки методу. Метод повідомляє про мету запиту клієнта.
Протокол HTTP підтримує досить багато методів, але реально
використовуються тільки три: POST, GET й HEAD. Метод GET дозволяє
одержати будь-які дані, ідентифіковані за допомогою URI у запиті ресурсу.
Якщо URI указує на програму, то повертається результат роботи програми, а
не її текст (якщо, звичайно, текст не є результат її роботи). Додаткова
інформація, необхідна для обробки запиту, вбудовується в сам запит (у рядок
статусу). При використанні методу GET у поле тіла ресурсу повертається
властиво викликана інформація (текст HTML-документа, наприклад).
30

Метод HEAD аналогічний методу GET, тільки не повертає тіло


ресурсу. Метод HEAD використовують для одержання інформації про
ресурс. Це може придатися, наприклад, при рішенні задачі тестування
гіпертекстових посилань.
Метод POST розроблений для передачі на сервер такої інформації, як
анотації ресурсів, новинні й поштові повідомлення, дані для додавання в базу
даних, тобто для передачі інформації великого обсягу й досить важливої. На
відміну від методів GET й HEAD, в POST передається тіло ресурсу, що й є
інформацією, що одержується з полів форм або інших джерел введення.
Далі ми розглянемо, як посилати запити серверу і як обробляти його
відповіді.

3.4 Використання HTML-форм для передачі даних на сервер

Як передавати дані серверу? Для цього в мові HTML є спеціальна


конструкція - форми. Форми призначені для того, щоб одержувати від
користувача інформацію. Наприклад, вам потрібно знати логін і пароль
користувача для того, щоб визначити, на які сторінки сайту його можна
допускати. Або вам необхідні особисті дані користувача, щоб була
можливість з ним зв'язатися. Форми саме й застосовуються для введення
такої інформації. У них можна вводити текст або вибирати відповідні
варіанти зі списку. Дані, записані у форму, відправляються для обробки
спеціальній програмі (наприклад, скрипту на PHP) на сервері. Залежно від
введених користувачами даних ця програма може формувати різні web-
сторінки, відправляти запити до бази даних, запускати різні додатки й т.п.
Для створення форми в мові HTML використовується елемент FORM.
Усередині нього знаходиться один або кілька елементів INPUT. За
допомогою атрибутів action й method тегу FORM задаються ім'я
програми, що буде обробляти дані форми, і метод запиту, відповідно. У тегу
INPUT атрибути визначають тип і різні характеристики запитуваної
інформації. Відправлення даних форми відбувається після натискання кнопки
INPUT типу submit. Створимо форму для реєстрації учасників заочної
школи програмування.

<h2>Форма для реєстрації учасників</h2>


<form action="1.php" method=POST><!--створюємо форму-->
<!--дані форми буде обробляти файл 1.php, при
відправленні запиту буде використаний метод POST-->
Ім'я <br><input type="text" name="first_name"
value="Уведіть Ваше ім'я"><br>
Прізвище <br><input type="text" name="last_name"><br>
E-mail <br><input type="text" name="email"><br>
<p>
Виберіть курс, що ви б хотіли відвідувати:<br>
<input type="radio" name="kurs" value="PHP">PHP<br>
31

<input type="radio" name="kurs" value="Perl">Perl<br>


<input type="radio" name="kurs" value="Unix">Unix<br>
<P>Що ви хочете, щоб ми знали про вас? <BR>
<textarea name="comment" cols=32 rows=5></textarea>
<P><input name="confirm" type="checkbox"
checked>Підтвердити одержання <br>
<input type="submit" value="Відправити">
<input type="reset" value="Скасувати">
</form>

Ось так створюються HTML-форми. У формі можна вказувати метод


передачі даних. Подивимося, що буде відбуватися, якщо вказати метод GET
або POST, і в чому буде різниця.

Метод GET

При відправленні даних форми за допомогою методу GET вміст форми


додається до URL після знака питання у вигляді пар ім'я=значення,
об'єднаних за допомогою амперсанда &:

action?name1=value1&name2=value2&name3=value3

Тут action - це URL-адреса програми, що повинна обробляти форму


(це або програма, задана в атрибуті action тегу form, або сама поточна
програма, якщо цей атрибут опущений). Імена name1, name2, name3
відповідають іменам елементів форми, а value1, value2, value3 -
значенням цих елементів. Всі спеціальні символи, включаючи = й &, в іменах
або значеннях цих параметрів будуть закодовані. Тому не варто використати
в назвах або значеннях елементів форми ці символи й символи кирилиці в
ідентифікаторах.
Якщо в поле для введення ввести який-небудь службовий символ, то
він буде переданий у його шістнадцятиричному коді, наприклад, символ $
заміниться на %24.
Для полів введення тексту й пароля (це елементи input з атрибутом
type="text" й type="password"), значенням буде те, що введе
користувач. Якщо користувач нічого не вводить у таке поле, то в рядку
запиту буде присутній елемент name=, де name відповідає імені цього
елемента форми.
Для кнопок типу checkbox й radio значення value визначається
атрибутом VALUE у тому випадку, коли кнопка відмічена. Не відмічені
кнопки при складанні рядка запиту ігноруються цілком. Кілька кнопок типу
checkbox можуть мати один атрибут NAME (і різні VALUE), якщо це
необхідно. Кнопки типу radio призначені для одного з всіх запропонованих
32

варіантів і тому повинні мати однаковий атрибут NAME і різні атрибути


VALUE.
В принципі створювати HTML-форму для передачі даних методом GET
не обов'язково. Можна просто додати в рядок URL потрібні змінні і їхні
значення:

http://phpbook.info/test.php?id=10&user=pit

У зв'язку з цим у передачі даних методом GET є один істотний недолік


- кожний може підробити значення параметрів. Тому не слід
використовувати цей метод для доступу до захищених паролем сторінок, для
передачі інформації, що впливає на безпеку роботи програми або сервера.
Крім того, не варто застосовувати метод GET для передачі інформації, що не
дозволено змінювати користувачеві.
Незважаючи на всі ці недоліки, використовувати метод GET досить
зручно при налагодженні скриптів (тоді можна бачити значення й імена
переданих змінних) і для передачі параметрів, що не впливають на безпеку.

Метод POST

Вміст форми кодується точно так само, як для методу GET, але замість
додавання рядка до URL вміст запиту посилається блоком даних як частина
операції POST. Якщо є присутнім атрибут ACTION, то значення URL, що
там перебуває, визначає, куди посилати цей блок даних. Цей метод, як ми
вже відзначали, рекомендується для передачі великих за обсягом блоків
даних.
Інформація, введена користувачем і відправлена серверу за допомогою
методу POST, подається на стандартне введення програмі, зазначеній в
атрибуті ACTION, або поточному скрипту, якщо цей атрибут опущений.
Довжина файлу, що посилається, передається в змінній оточення
CONTENT_LENGTH, а тип даних - у змінній CONTENT_TYPE.
Передати дані методом POST можна тільки за допомогою HTML-
форми, оскільки дані передаються в тілі запиту, а не в заголовку, як в GET.
Відповідно й змінити значення параметрів можна, тільки змінивши значення,
введене у форму. При використанні POST користувач не бачить передані
серверу дані.
Основна перевага POST запитів - це їхня більша безпека й
функціональність у порівнянні з GET-запитами. Тому метод POST частіше
використовують для передачі важливої інформації, а також інформації
великого обсягу. Проте не варто цілком покладатися на безпеку цього
механізму, оскільки дані POST запиту також можна підробити, наприклад
створивши html-файл на своїй машині й заповнивши його потрібними
даними. Крім того, не всі клієнти можуть застосовувати метод POST, що
обмежує варіанти його використання.
33

При відправленні даних на сервер будь-яким методом передаються не


тільки самі дані, введені користувачем, але й ряд змінних, що називаються
змінними оточення та характеризують клієнта, історію його роботи, шляхи
до файлів і т.п. Ось деякі зі змінних оточення:
 REMOTE_ADDR - IP-адреса хоста (комп'ютера), що відправляє запит;
 REMOTE_HOST - ім'я хоста, з якого відправлений запит;
 HTTP_REFERER - адреса сторінки, що посилається на поточний
скрипт;
 REQUEST_METHOD - метод, що був використаний при відправленні
запиту;
 QUERY_STRING - інформація, що перебуває в URL після знака
питання;
 SCRIPT_NAME - віртуальний шлях до програми, що повинна
виконуватися;
 HTTP_USER_AGENT - інформація про браузер, що використовує
клієнт.

3.7 Обробка запитів за допомогою PHP

Дотепер ми згадували тільки, що запити клієнта обробляються на


сервері за допомогою спеціальної програми. Насправді цю програму ми
можемо написати самі, у тому числі й мовою PHP, і вона буде робити з
отриманими даними все, що ми захочемо. Для того, щоб написати цю
програму, необхідно познайомитися з деякими правилами й інструментами,
що пропонуються для цих цілей PHP.
Усередині PHP-скрипта є кілька способів одержання доступу до даних,
переданих клієнтом по протоколу HTTP. До версії PHP 4.1.0 доступ до таких
даних здійснювався по іменах переданих змінних (нагадаємо, що дані
передаються у вигляді пар «ім'я змінної, символ «=», значення змінної»).
Таким чином, якщо, наприклад, було передано first_name=Nina, те
усередині скрипта з'являлася змінна $first_name зі значенням Nina.
Якщо було потрібно розрізняти, яким методом були передані дані, то
використовувалися асоціативні масиви $HTTP_POST_VARS й
$HTTP_GET_VARS, ключами яких були імена переданих змінних, а
значеннями - відповідно значення цих змінних. Таким чином, якщо пара
first_name=Nina передана методом GET, то
$HTTP_GET_VARS["first_name"]= "Nina".
Використовувати в програмі імена переданих змінних прямо
небезпечно. Тому було вирішено починаючи з PHP 4.1.0 задіяти для
звертання до змінних, переданих за допомогою HTTP-запитів, спеціальний
масив - $_REQUEST. Цей масив містить дані, передані методами POST й
GET, а також за допомогою HTTP cookies. Це суперглобальний асоціативний
масив, тобто його значення можна одержати в будь-якому місці програми,
використовуючи як ключ ім'я відповідної змінної (елемента форми).
34

Приклад. Припустимо, ми створили форму для реєстрації учасників заочної


школи програмування, як у наведеному вище прикладі. Тоді у файлі 1.php,
що обробляє цю форму, можна написати наступне:

<?php
$str = "Здрастуйте, ".$_REQUEST["first_name"]. "
".$_REQUEST["last_name"]."! <br>";
$str .="Ви вибрали для вивчення курс по
".$_REQUEST["kurs"];
echo $str;
?>

Тоді, якщо у форму ми ввели ім'я «Андрій», прізвище «Петров» і


вибрали серед всіх курсів курс по PHP, на екрані браузера одержимо таке
повідомлення:

Здрастуйте, Андрій Петров!


Ви вибрали для вивчення курс по PHP

Після введення масиву $_REQUEST масиви $HTTP_POST_VARS й


$HTTP_GET_VARS для однорідності були перейменовані в $_POST й $_GET
відповідно, але самі вони з обігу не зникли з міркувань сумісності з
попередніми версіями PHP. На відміну від своїх попередників, масиви
$_POST й $_GET стали суперглобальними, тобто доступними прямо й
усередині функцій і методів.
Наведемо приклад використання цих масивів. Припустимо, нам
потрібно обробити форму, що містить елементи введення з іменами
first_name, last_name, kurs (наприклад, форму form.html, наведену
вище). Дані були передані методом POST, і дані, передані іншими методами,
ми обробляти не хочемо. Це можна зробити в такий спосіб:

<?php
$str = "Здрастуйте, ".$_POST["first_name"]."
".$_POST["last_name"] ."! <br>";
$str .= "Ви вибрали для вивчення курс по
".$_POST["kurs"];
echo $str;
?>

Тоді на екрані браузера, якщо ми ввели ім'я «Андрій», прізвище


«Петров» і вибрали серед всіх курсів курс по PHP, побачимо повідомлення,
як у попередньому прикладі:

Здрастуйте, Андрій Петров!


Ви вибрали для вивчення курс по PHP
35

Для того, щоб зберегти можливість обробки скриптів більш ранніх


версій, ніж PHP 4.1.0, була введена директива register_globals, що
дозволяє або забороняє доступ до змінних безпосередньо по їхніх іменах.
Якщо у файлі настроювань PHP параметр register_globals=On, то до
змінних, переданих серверу методами GET й POST, можна звертатися просто
по їхніх іменах (тобто можна писати $first_name). Якщо ж
register_globals=Off, то потрібно писати
$_REQUEST["first_name"] або $_POST["first_name"],
$_GET["first_name"], $HTTP_POST_VARS["first_name"],
$HTTP_GET_VARS["first_name"]. З погляду безпеки цю директиву
краще відключати (тобто register_globals=Off). При включеній
директиві register_globals перераховані вище масиви також будуть
містити дані, передані клієнтом.
Іноді виникає необхідність довідатися значення якої-небудь змінної
оточення, наприклад метод, що використовувався при передачі запиту або IP-
адреса комп'ютера, що відправив запит. Одержати таку інформацію можна за
допомогою функції getenv(). Вона повертає значення змінної оточення,
ім'я якої передане їй як параметр.

<?php
getenv('REQUEST_METHOD');
// поверне використаний метод
echo getenv('REMOTE_ADDR');
// виведе IP-адресу користувача, що послав запит
?>

Як ми вже говорили, якщо використовується метод GET, то дані


передаються додаванням рядка запиту у вигляді пар «ім'я_змінної=значення»
до URL-адреси ресурсу. Усе, що записано в URL після знака питання, можна
одержати за допомогою команди

getenv('QUERY_STRING');

Методом POST дані передаються тільки за допомогою форм, і


користувач (клієнт) не бачить, які саме дані відправляються серверу. Щоб їх
побачити, хакер повинен підмінити нашу форму своєю. Тоді сервер
відправить результати обробки неправильної форми не туди, куди потрібно.
Щоб цього уникнути, можна перевіряти адресу сторінки, з якої були послані
дані. Це можна зробити знову ж за допомогою функції getenv():

getenv('HTTP_REFERER');
36

4 РОБОТА З МАСИВАМИ ДАНИХ

Мова PHP надає безліч функцій для роботи з масивами даних. Як


правило, ці функції вирішують задачі, пов'язані з обробкою масивів, що
найбільш часто зустрічаються. Розглянемо деякі з таких функцій.

Масиви

Нагадаємо, що масив можна створити двома способами:


1. За допомогою конструкції array
$array_name = array("key1"=>"value1",
"key2"=>"value2");
2. Безпосередньо задаючи значення елементам масиву
$array_name["key1"] = value1;
Наприклад, нам потрібно зберігати список документів, які будуть
вилучені з бази даних. Природно зберігати його у вигляді масиву, ключем у
якому буде ідентифікатор документа (його унікальний номер), а значенням -
назва документа. Цей масив можна створити в такий спосіб:

<?php
$del_items = array("10"=>"Програмування на Perl",
"12"=>"Інформатика");
$del_items["13"] = "Програмування на Php";
// додаємо елемент у масив
?>

4.1 Операції з масивами

Масив - це тип даних, з даними цього типу повинні бути визначені


операції. Які ж операції можна робити з масивами? Масиви можна складати й
порівнювати.
Складають масиви за допомогою стандартного оператора «+». Загалом
кажучи, цю операцію стосовно масивів точніше назвати об'єднанням. Якщо в
нас є два масиви, $a й $b, то результатом їхнього додавання (об'єднання)
буде масив $c, що складається з елементів $a, до яких праворуч дописані
елементи масиву $b. Причому, якщо зустрічаються співпадаючі ключі, то в
результуючий масив включається елемент з першого масиву, тобто з $a.
Таким чином, якщо складаються масиви в мові PHP, від зміни місць доданків
сума міняється.

<?php
$a = array("і"=>"Інформатика",
"м"=>"Математика");
$b = array("і"=>"Історія","м"=>"Біологія",
37

"ф"=>"Фізика");
$c = $a + $b;
$d = $b + $a;
print_r($c);
/* одержимо: Array([і]=>Інформатика
[м]=>Математика [ф]=>Фізика) */
print_r($d);
/* одержимо: Array([і]=>Історія
[м]=>Біологія [ф]=>Фізика) */
?>

Порівнювати масиви можна, перевіряючи їхню рівність чи нерівність


або еквівалентність чи нееквівалентність. Рівність масивів - це коли
співпадають всі пари ключ/значення елементів масивів. Еквівалентність -
коли крім рівності значень і ключів елементів потрібно ще, щоб елементи в
обох масивах були записані в тому самому порядку. Рівність значень в PHP
позначається символом «==», а еквівалентність - символом «===».

<?php
$a = array("і"=>"Інформатика",
"м"=>"Математика");
$b = array("м"=>"Математика",
"і"=>"Інформатика");
if ($a == $b) echo "Масиви рівні й";
else echo "Масиви НЕ рівні й ";
if ($a === $b) echo " еквівалентні";
else echo " НЕ еквівалентні";
// одержимо echo "Масиви рівні й НЕ еквівалентні"
?>

Функція count

Функція count() - підрахунок кількості елементів масиву.


Насправді ця функція обчислює число елементів у змінній взагалі.
Якщо застосувати її до будь-якої іншої змінної, вона поверне 1. Виключення
становить змінна типу NULL - count(NULL) є 0. Крім того, застосовуючи
цю функцію до багатомірного масиву, щоб одержати число його елементів,
потрібно використати додатковий параметр COUNT_RECURSIVE.

<?php
$del_items = array("langs" => array(
"10"=>"Python", "12"=>"Lisp"),
"other"=>"Інформатика");
echo count($del_items)."<br>";
// виведе 2
38

echo count($del_items,COUNT_RECURSIVE);
// виведе 4
?>

Функція in_array

in_array("шукане значення","масив", ["обмеження на


тип"]);

дозволяє встановити, чи міститься в заданому масиві шукане значення. Якщо


третій аргумент заданий як true, то в масиві потрібно знайти елемент, що
співпадає з шуканим не тільки за значенням, але й за типом. Якщо шукане
значення - рядок, то порівняння відчутно до регістра.
Наприклад, є масив не вивчених нами мов програмування. Ми хочемо
довідатися, чи міститься в цьому масиві мова PHP. Напишемо наступну
програму:

<?php
$langs = array("Lisp","Python","Java",
"PHP","Perl");
if (in_array("PHP",$langs,true))
echo "Треба б вивчити PHP<br>";
// виведе повідомлення "Треба б вивчити PHP"
if (in_array("php",$langs))
echo "Треба б вивчити php<br>";
// нічого не виведе, оскільки в масиві
// є рядок "PHP", а не "php"
?>

В якості шуканого значення цієї функції може виступати й масив.


Правда, ця властивість була додана тільки починаючи з PHP 4.2.0.
Наприклад:

<?php
$langs =
array("Lisp","Python",array("PHP","Java"),"Perl");
if (in_array(array("PHP","Java"),$langs))
echo "Треба б вивчити PHP й Java<br>";
?>

Функція array_search

Це ще одна функція для пошуку значення в масиві. На відміну від


in_array у результаті роботи array_search повертає значення ключа,
39

якщо елемент знайдений, і false - у противному випадку. А от синтаксис у


цих функцій однаковий:
array_search("шукане значення","масив", ["обмеження на
тип"]);

Порівняння рядків відчутно до регістра, а якщо зазначено значення


TRUE у якості необов'язкового третього параметра, то порівнюються ще й
типи значень. До PHP 4.2.0, якщо шукане значення не було знайдено, ця
функція повертала помилку або порожнє значення NULL.

Приклад. Тепер, навпаки, нехай у нас є масив мов програмування, які ми


знаємо. Причому ключем кожного елемента є номер, що вказує, якою за
рахунком була вивчена ця мова.

<?php
$langs = array("","Lisp","Python","Java",
"PHP","Perl");
if (!array_search("PHP",$langs))
echo "Треба б вивчити PHP<br>";
else {
$k = array_search("PHP",$langs);
echo "Мову PHP я вивчила $k-ою";
}
?>

У результаті ми одержимо рядок:

Мову PHP я вивчила 4-ою

Очевидно, що ця функція більш функціональна, ніж in_array,


оскільки ми не тільки одержуємо інформацію про те, що шуканий елемент у
масиві є, але й довідаємося, де саме в масиві він перебуває. А що буде, якщо
шуканих елементів у масиві кілька? У такому випадку функція
array_search() поверне ключ першого зі знайдених елементів. Щоб
одержати ключі всіх елементів, потрібно скористатися функцією
array_keys().

Функція array_keys

Функція array_keys() вибирає всі ключі масиву. Але в неї є


додатковий аргумент, за допомогою якого можна одержати список ключів
елементів з конкретним значенням. Синтаксис цієї функції такий:
array_keys ("масив", ["значення для пошуку"])
40

Функція array_keys() повертає як строкові, так і числові ключі


масиву, організовуючи всі значення у вигляді нового масиву з числовими
індексами.
Приклад. Ми записали масив мов, які вивчили. Список був довгим, і деякі
мови були записані кілька разів. У нас виникла підозра, що один з таких мов
- Lisp. Давайте це перевіримо:

<?php
$langs = array("Lisp","Python","Java","PHP",
"Perl","Lisp");
$lisp_keys = array_keys($langs,"Lisp");
echo "Lisp входить у масив ".
count($lisp_keys)." рази:<br>";
foreach ($lisp_keys as $val){
echo "під номером $val <br>";
}
?>

У результаті одержимо:

Lisp входить у масив 2 рази:


під номером 0
під номером 5

Функція array_keys(), як і дві попередні, залежить від регістра,


тобто елементів LISP у масиві вона не знайде. Функція array_keys()
з'явилася тільки в PHP4.
Якщо є функція для одержання всіх ключів масиву, то можна
припустити, що існує й функція для одержання всіх значень масиву. Дійсно,
вона існує. Це функція array_values(масив). Всі значення переданого
їй масиву записуються в новий масив, проіндексований цілими числами,
тобто всі ключі масиву губляться, залишаються тільки значення.
Але повернемося до нашого приклада. Отже, ми з'ясували, що мова
Lisp випадково згадана у нашому масиві двічі. Оскільки вивчити одну мову
двічі не можна, то потрібно якось позбутися від мов, що повторюються.
Зробити це досить просто за допомогою функції array_unique().

Функція array_unique

Функція array_unique(масив) повертає новий масив, у якому


елементи, що повторюються, фігурують в одному екземплярі. Таким чином,
замість декількох однакових значень й їхніх ключів ми маємо одне значення.
Який у нього буде ключ? Як з декількох ключів однакових елементів
вибирається той, котрий буде збережений у новому масиві? Відбувається
41

наступне. Всі елементи масиву перетворяться в рядки й сортуються. Потім


оброблювач запам'ятовує перший ключ для кожного значення, а інші ключі
ігнорує.
Спробуємо позбутися від мов, що повторюються, у списку вивчених.
<?php
$langs = array("Lisp","Java","Python","Java",
"PHP","Perl","Lisp");
print_r(array_unique($langs));
?>

Одержимо наступне:

Array ( [0] => Lisp [1] => Java [2] => Python [4] =>
PHP [5] => Perl )

Далі розглянемо задачу сортування масиву.

4.2 Сортування масивів

Необхідність сортування даних, у тому числі й даних, що зберігаються


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

Функція sort

Функція sort має наступний синтаксис

sort (масив [, прапори])

і сортує масив, тобто впорядковує його значення по зростанню. Ця функція


видаляє всі існуючі в масиві ключі, заміняючи їхніми числовими індексами,
що відповідають новому порядку елементів. У випадку успішного
завершення роботи вона повертає true, інакше - false.

Приклад. Нехай у нас є два масиви: ціни товарів - їхні назви й, навпаки,
назви товарів - їхні ціни. Упорядкуємо ці масиви по зростанню:

<?php
$items = array(10 => "хліб", 20 => "молоко",
30 => "бутерброд");
sort($items);
// рядки сортуються в алфавітному
// порядку, ключі губляться
42

print_r($items);

$rev_items = array("хліб" => 10,


"бутерброд" => 30, "молоко" => 20);
sort($rev_items);
// числа сортуються по зростанню,
// ключі губляться
print_r($rev_items);
?>

Одержимо:

Array ( [0] => бутерброд [1] => молоко [2] => хліб )
Array ( [0] => 10 [1] => 20 [2] => 30)

Як додатковий аргумент може використовуватися одна з наступних


констант:
 SORT_REGULAR - порівнювати елементи масиву звичайним образом;
 SORT_NUMERIC - порівнювати елементи масиву як числа;
 SORT_STRING - порівнювати елементи масиву як рядки.

Функції asort, rsort, arsort

Якщо потрібно зберігати індекси елементів масиву після сортування, то


потрібно використати функцію asort(масив [, прапори]). Якщо
необхідно відсортувати масив у зворотному порядку, тобто від найбільшого
значення до найменшого, то можна задіяти функцію rsort(масив [,
прапори]). А якщо при цьому потрібно ще й зберегти значення ключів, то
варто використати функцію arsort(масив [, прапори]). Як ви,
напевно, помітили, синтаксис у цих функцій абсолютно такий же, як у
функції sort. Відповідно й значення прапорів можуть бути такими ж, як в
sort: SORT_REGULAR, SORT_NUMERIC, SORT_STRING.

Приклад. Застосування функцій asort, rsort, arsort

<?php
$books = array("Еккель Б."=>"Філософія Java",
"Прохоренок Н."=>"Новий стиль програмування на
JavaScript",
"Вейл Е."=>"Розробка додатків для мобільних
пристроїв");
asort($books);
// сортуємо масив, зберігаючи значення ключів
print_r($books);
43

echo "<br>";
rsort($books);
// сортуємо масив у зворотному порядку,
// ключі будуть замінені
print_r($books);
?>

У результаті роботи цього скрипта одержимо:

Array ([Прохоренок Н.] => Новий стиль програмування на


JavaScript
[Вейл Е.] => Розробка додатків для мобільних
пристроїв
[Еккель Б.] => Філософія Java)
Array ([0] => Філософія Java
[1] => Розробка додатків для мобільних пристроїв
[2] => Новий стиль програмування на JavaScript)

Приклад. Припустимо, ми створюємо каталог описів документів. У кожного


документа є автор, назва, дата публікації й короткий зміст. Ми хочемо мати
можливість змінювати порядок відображення елементів за бажанням
користувача. Складемо для цього наступну форму:

<form action="task.php">
<table border=1>
<tr><td>Назва </td><td><input type="text"
name="title" size=5> </td></tr>
<tr><td>Короткий зміст </td><td><input
type="text" name="description" size=5>
</td></tr>
<tr><td>Автор </td><td><input type="text"
name="author" size=5> </td></tr>
<tr><td>Дата публікації </td><td><input
type="text" name="published" size=5></td></tr>
</table>
<input type="submit" value="Відправити">
</form>

Будемо впорядковувати дані, передані цією формою, по убуванню їхніх


значень, зберігаючи при цьому значення ключів. Для цього зручно
скористатися функцією arsort(). Оскільки нам важливий тільки новий
порядок елементів, збережемо в новому масиві ключі вихідного масиву в
потрібному порядку. Ми зберігаємо ключі вихідного масиву, оскільки вони є
іменами елементів, з яких конструюється опис документа, а пам'ятати їх
важливо. Отже, одержуємо такий скрипт:
44

<?php
print_r($_GET); echo "<br>";
arsort ($_GET); // сортуємо масив у зворотному порядку,
зберігаючи ключі
print_r($_GET); echo "<br>";
$ordered_names = array_keys($_GET); // складаємо новий
масив
foreach($ordered_names as $key => $val)
echo "$key :$val <br>"; // виводимо елементи
нового масиву
?>

Сортування масиву по ключах

Очевидно, що може виникнути необхідність у сортуванні масиву за


значеннями ключів. Наприклад, якщо в нас є масив даних про книги, як у
наведеному вище прикладі, то цілком імовірно, що ми захочемо відсортувати
книги по іменах авторів. Для цього в PHP також не потрібно писати багато
рядків коду - можна просто скористатися функцією ksort() для сортування
по зростанню (прямий порядок сортування) або krsort() - для сортування
по убуванню (зворотний порядок сортування). Синтаксис цих функцій знову
ж аналогічний синтаксису функції sort().

Приклад. Сортування масиву по ключах

<?php
$books = array("Еккель Б."=>"Філософія Java",
"Прохоренок Н."=>"Новий стиль програмування на
JavaScript",
"Вейл Е."=>"Розробка додатків для мобільних
пристроїв");
ksort($books);
// сортуємо масив, зберігаючи значення ключів
print_r($books);
?>

Одержимо:

Array ([Вейл Е.] => Розробка додатків для мобільних


пристроїв
[Еккель Б.] => Філософія Java
[Прохоренок Н.] => Новий стиль програмування на
JavaScript)
45

Сортування за допомогою функції, заданої користувачем

Крім двох простих способів сортування значень масиву (по убуванню


або по зростанню), PHP пропонує користувачеві можливість самому задавати
критерії для сортування даних. Критерій задається за допомогою функції,
ім'я якої вказується як аргумент для спеціальних функцій сортування
usort() або uksort(). По назвах цих функцій можна догадатися, що
usort() сортує значення елементів масиву, а uksort() - значення ключів
масиву за допомогою визначеної користувачем функції. Обидві функції
повертають true, якщо сортування пройшло успішно, і false - у
противному випадку. Їхній синтаксис виглядає наступним чином:

usort (масив , функція)


uksort (масив , функція)

Звичайно ж, не можна сортувати масив за допомогою будь-якої


користувальницької функції. Ця функція повинна задовольняти певним
критеріям, що дозволяють порівнювати елементи масиву. Як повинна бути
влаштована функція, що сортує? По-перше, вона повинна мати два
аргументи. У них інтерпретатор буде передавати пари значень елементів для
функції usort() або ключів масиву для функції uksort(). По-друге,
функція, що сортує, повинна повертати:
 ціле число, менше нуля, якщо перший аргумент менше другого;
 число, рівне нулю, якщо два аргументи рівні;
 число більше нуля, якщо перший аргумент більше другого.
Як і для інших функцій сортування, для функції usort() існує аналог,
що не змінює значення ключів, - функція uasort().

Приклад. Припустимо, у нас є масив, що містить такі відомості про


літературні твори, як назва, автор і рік створення. Ми хочемо впорядкувати
книги по даті створення.

<?php
// масив виглядає в такий спосіб:
$books = array("Філософія Java" =>
array ("Еккель Б.", 2009),
"Новий стиль програмування на JavaScript" =>
array("Прохоренок Н.",2010),
"Розробка додатків для мобільних пристроїв" => array
("Вейл Е.",2008));
/* можна, звичайно переписати цей масив
по-іншому, зробивши рік видання, наприклад,
індексом, але набагато зручніше написати свою
функцію для сортування */
46

uasort($books,"cmp");
// сортуємо масив за допомогою функції cmp

foreach ($books as $key => $book) {


echo "$book[0]: \"$key\"<br>";
}
function cmp($a,$b){
// функція, що визначає спосіб сортування
if ($a[1] < $b[1]) return -1;
elseif ($a[1]==$b[1]) return 0;
else return 1;
}
?>

У результаті одержимо:

Вейл Е.: "Розробка додатків для мобільних пристроїв"


Еккель Б.: "Філософія Java"
Прохоренок Н.: "Новий стиль програмування на
JavaScript"

4.3 Виділення підмасива

Функція array_slice

Оскільки масив - це набір елементів, цілком імовірно, буде потрібно


виділити з нього який-небудь поднабор. В PHP для цих цілей є функція
array_slice. Її синтаксис такий:

array_slice (масив, номер_елемента [, довжина])

Ця функція виділяє підмасив довжини довжина в масиві масив,


починаючи з елемента, номер якого заданий параметром номер_елемента.
Позитивний номер_елемента вказує на порядковий номер елемента
відносно початку масиву, негативний - на номер елемента з кінця масиву.

Приклад. Використання функції array_slice()

<?php
$arr = array(1,2,3,4,5);
$sub_arr = array_slice($arr,2);
print_r($sub_arr);
/*
виведе Array ( [0] => 3 [1] =>4 [2] => 5 ),
47

підмасив, що складається з елементів 3, 4, 5 */


$sub_arr = array_slice($arr,-2);
print_r($sub_arr);
// виведе Array ( [0] => 4 [1] => 5 ),
// підмасив з елементів 4, 5
?>

Якщо задати параметр довжина при використанні array_slice, то


буде виділений підмасив, що має рівно стільки елементів, скільки задано цим
параметром. Довжину можна вказувати й негативну. У цьому випадку
інтерпретатор видалить з кінця масиву число елементів, рівне модулю
параметра довжина.

Приклад. Використання функції array_slice(). Варіант 2

<?php
$arr = array(1,2,3,4,5);
$sub_arr = array_slice($arr, 2, 2);
// містить масив з елементів 3, 4
$sub = array_slice($arr,-3, 2);
// теж містить масив з елементів 3, 4
$sub1 = array_slice($arr,0, -1);
// містить масив з елементів 1, 2, 3, 4
$sub2 = array_slice($arr,-4, -2);
// містить масив з елементів 2, 3
?>

Функція array_chunk

Є ще одна функція, схожа на array_slice() - це array_chunk().


Вона розбиває масив на кілька підмасивів заданої довжини. Синтаксис її
такий:

array_chunk (масив, розмір [, зберігати_ключі])

У результаті роботи array_chunk() повертає багатомірний масив,


елементи якого являють собою отримані підмасиви. Якщо задати параметр
зберігати_ключі як true, то при розбивці будуть збережені ключі
вихідного масиву. У противному випадку ключі елементів заміняються
числовими індексами, які починаються з нуля.

Приклад. У нас є список запрошених, оформлений у вигляді масиву їхніх


прізвищ. У нас є столики на три персони. Тому потрібно розподілити всіх
запрошених по три.
48

<?php
$persons = array("Бондарчук", "Петренко",
"Тарасюк","Ткаченко", "Пасічник");
$triples = array_chunk($persons,3);
// ділимо масив на підмасиви по три елементи
foreach ($triples as $k => $table){
// виводимо отримані трійки
echo "За столиком номер $k сидять: <ul>";
foreach ($table as $pers)
echo "<li>$pers";
echo "</ul>";
}
?>

У результаті одержимо:

За столиком номер 0 сидять:

• Бондарчук
• Петренко
• Тарасюк

За столиком номер 1 сидять:

• Ткаченко
• Пасічник
49

5 РОБОТА З РЯДКАМИ

У даному розділі більш докладно обговорюються питання роботи з


рядками, вивчаються функції, корисні для рішення різноманітних
прикладних завдань. Розглядаються різні способи виводу рядків, розбивка й
з'єднання рядків (функції explode, implode), визначення довжини рядка
(strlen), виділення підрядка (strstr, substr).

Рядки

Раніше були наведені способи завдання рядків за допомогою


одинарних лапок і подвійних лапок. Відзначалися основні розходження між
цими способами. В основному вони стосуються обробки змінних і керуючих
послідовностей усередині рядка.

<?php
echo 'У такому рядку НЕ обробляються
змінні й більшість послідовностей';
echo "Тут змінні й послідовності обробляються";
?>

Уже не раз ми використовували функцію echo. Насправді, echo - не


функція, а язикова конструкція, тому використовувати при її виклику круглі
дужки не обов'язково. Echo дозволяє виводити на екран рядки, передані їй
як параметри. Параметрів в echo може бути скільки завгодно. Їх розділяють
комами або поєднують за допомогою оператора конкатенації й ніколи не
беруть у круглі дужки.

<?php
echo "Прийшов ", "побачив ", "переміг ";
// виведе рядок "Прийшов побачив переміг"
echo "Прийшов " . "побачив " . "переміг ";
// теж виведе рядок "Прийшов побачив переміг"
echo("Прийшов ", "побачив ", "переміг ");
// видасть помилку: unexpected ','
?>

5.1 Пошук елемента в рядку

Для того щоб визначити, чи входить даний підрядок до складу рядка,


використовується функція strpos(). Синтаксис strpos() такий:
strpos (вихідний рядок, рядок для пошуку [,з якого
символу шукати])
50

Вона повертає позицію появи шуканого рядка у вихідному рядку або


повертає логічне false, якщо входження не знайдене. Додатковий аргумент
дозволяє задавати символ, починаючи з якого буде виконуватися пошук.
Крім логічного false, ця функція може повертати й інші значення, які
приводяться до false (наприклад, 0 або ""). Тому для того, щоб перевірити,
чи знайдений шуканий рядок, рекомендують використовувати оператор
еквівалентності «===».

<?php
$mystring = 'abc';
$findme = 'a';
$pos = strpos($mystring, $findme);

// Зауважте, що використовується ===. Використання ==


не дасть вірного
// результату, так як 'a' знаходиться в нульовій
позиції.
if ($pos === false) {
echo " Рядок '$findme' не знайдено в
рядку '$mystring'";
} else {
echo " Рядок '$findme' знайдено в
рядку '$mystring'";
echo " в позиции $pos";
}
?>

Якщо значення параметра рядок_для_пошуку не є рядком, то воно


перетвориться до цілого типу й розглядається як ASCII-код символу. Щоб
одержати ASCII-код будь-якого символу в PHP, можна скористатися
функцією ord("символ").
Функція, зворотна за змістом ord, - це chr(код символу). Вона по
ASCII-коду виводить символ, що відповідає цьому коду.
За допомогою функції strpos можна знайти номер тільки першої
появи рядка у вихідному рядку. Природно, є функції, які дозволяють
обчислити номер останньої появи рядка у вихідному рядку. Це функція
strrpos(). Її синтаксис такий:

strrpos (вихідний рядок, символ для пошуку)

На відміну від strpos(), ця функція дозволяє знайти позицію


останньої появи в рядку зазначеного символу.
Бувають ситуації, коли знати позицію, де перебуває шуканий рядок,
необов'язково, а потрібно просто одержати всі символи, які розташовані
51

після входження цього рядка. Можна, звичайно, скористатися й наведеними


вище функціями strpos() і strrpos(), але можна зробити й простіше -
виділити підрядок за допомогою призначених саме для цього функцій.

5.2 Виділення підрядка

Функція strstr

Говорячи про виділення підрядка з шуканого рядка в мові PHP, у


першу чергу варто відзначити функцію strstr():

strstr (вихідний рядок, рядок для пошуку)

Вона знаходить першу появу шуканого рядка й повертає підрядок,


починаючи з цього шуканого рядка до кінця вихідного рядка.
Якщо рядок для пошуку не знайдений, то функція поверне false.
Якщо рядок для пошуку не належить строковому типу даних, то він
переводиться в ціле число й розглядається як код символу. Крім того, ця
функція чутлива до регістра, тобто якщо ми будемо паралельно шукати
входження слів «Ідея» й «ідея», те результати будуть різними. Замість
strstr() можна використати абсолютно ідентичну їй функцію strchr().

Приклад. Виділимо з рядка, що містить назву й автора дослідження,


підрядок, що починається зі слова «Назва»:

<?php
$str = "Автор: Ткаченко Іван (<a
href=mailto:van@ukr.net>написати лист</a>),
Назва: 'Дослідження мов програмування' ";
echo "<b>Вихідний рядок: </b>",$str;
if (!strstr($str, "Назва"))
echo "Рядок не знайдений<br>";
else echo "<p><b>Отриманий підрядок: </b>",strstr($str,
"Назва");
?>

У результаті одержимо:

Вихідний рядок: Автор: Ткаченко Іван (написати лист),


Назва: 'Дослідження мов програмування'
Отриманий підрядок: Назва: 'Дослідження мов
програмування'

Для реалізації регістронезалежного пошуку підрядка існує відповідний


аналог цієї функції - функція stristr (вихідний рядок, шуканий
52

рядок). Діє й використовується вона точно так само, як й strstr(), за


винятком того, що регістр, у якому записані символи шуканого рядка, не грає
ролі при пошуку.

Функція substr

Іноді ми не знаємо, з яких символів починається шуканий рядок, але


знаємо, наприклад, що починається він з п'ятого символу й закінчується за
два символи до кінця вихідного рядка. Як виділити підрядок за таким
описом? Дуже просто, за допомогою функції substr(). Її синтаксис можна
записати в такий спосіб:

substr (вихідний рядок, позиція початкового символу [,


довжина])

Ця функція повертає частину рядка довжиною, заданою параметром


довжина, починаючи з символу, зазначеного параметром позиція
початкового символу. Позиція, з якої починається підрядок, що
виділяється, може бути як позитивним цілим числом, так і негативним. В
останньому випадку відлік елементів виконується з кінця рядка. Якщо
параметр довжина опущений, то substr() повертає підрядок від
зазначеного символу й до кінця вихідного рядка. Довжина підрядка, що
виділяється, теж може бути задана негативним числом. Це означає, що
зазначене число символів відкидається з кінця рядка.

Приклад. Припустимо, у нас є фраза, виділена жирним шрифтом за


допомогою тегу <b> мови HTML. Ми хочемо одержати цю ж фразу, але у
звичайному стилі. Напишемо таку програму:

<?php
$word = "<b>Hello, world!</b>";
echo $word , "<br>";
$pure_str = substr($word, 3, -4);
/* виділяємо підрядок,
починаючи з 3-го символу,
не включаючи 4 символи з кінця рядка */
echo $pure_str;
?>

У результаті роботи цього скрипта одержимо:

Hello, world!
Hello, world!
53

Насправді вирішити таке завдання можна набагато простіше, за


допомогою функції strip_tags:
strip_tags (рядок [, припустимі теги])

Ця функція повертає рядок, з якого вилучені всі html й php-теги. За


допомогою додаткового аргументу можна задати теги, які не будуть вилучені
з рядка. Список з декількох тегів вводиться без яких-небудь знаків
роздільників. Функція видає попередження, якщо зустрічають неправильні
або неповні теги.

<?php
$string = "<b>Bold text</b>
<i>Italic text</i>";
$str = strip_tags($string);
// видаляємо всі теги з рядка
$str1 = strip_tags($string, '<b>');
// видаляємо всі теги крім тегу <b>
$str2 = strip_tags($string, '<i>');
// видаляємо всі теги крім тегів <i>
echo $str,"<br>",$str1,"<br>", $str2;
?>

У результаті одержимо:

Bold text Italic text


Bold text Italic text
Bold text Italic text

Якщо нам потрібно одержати один конкретний символ з рядка, знаючи


його порядковий номер, то не слід задіяти функції типу substr. Можна
скористатися більш простим синтаксисом - записуючи номер символу у
фігурних дужках після імені строкової змінної. У контексті попереднього
приклада букву «B», розташовану четвертою за рахунком, можна одержати
так:

echo $string{3}; // виведе символ "B"

Помітимо, що номером цього символу є число 3, а не чотири, тому що


нумерація символів рядка починається з нуля.
Коли ми почали говорити про символи в рядку і їхню нумерацію, то
мимоволі виникає питання, скільки всього символів у рядку і як це
обчислити. Число символів у рядку - це довжина рядка. Обчислити довжину
рядка можна за допомогою функції strlen(рядок). Наприклад, довжина
54

рядка «Hello, world» обчислюється за допомогою команди:


strlen("Hello, world"); і дорівнює 12 символам.
Отже, як виділяти й знаходити підрядки, ми розглянули. Тепер
навчимося заміняти рядок, що входить до складу вихідного рядка, на інший
рядок за нашим вибором.

5.3 Заміна входження підрядка

Функція str_replace

Для заміни входження підрядка можна використати функцію


str_replace(). Синтаксис функції str_replace() такий:

str_replace(шукане значення, значення для заміни,


об'єкт)

Функція str_replace() шукає в розглянутому об'єкті значення й


заміняє його значенням, призначеним для заміни. Чому ми говоримо тут не
про рядки для пошуку й заміни й вихідний рядок, а про значення й об'єкт, у
якому відбувається заміна? Справа в тому, що починаючи з PHP 4.0.5 будь-
який аргумент цієї функції може бути масивом.
Якщо об'єкт, у якому здійснюється пошук і заміна, є масивом, то ці дії
виконуються для кожного елемента масиву й у результаті повертається новий
масив.

Приклад. Використання функції str_replace()

<?php
$greeting = array("Привіт", "Привіт всім!",
"Привіт, друзі!"); // об'єкт
$new_greet = str_replace("Привіт",
"Добрий ранок", $greeting);
// робимо заміну
print_r($new_greet);
/* одержимо: Array ([0]=>Добрий ранок [1]=>Добрий ранок
всім!
[2]=>Добрий ранок, друзі!) */
?>

Якщо шукане значення й значення для заміни - масиви, то береться по


одному значенню з кожного масиву й здійснюється їхній пошук і заміна в
об'єкті. Якщо значень для заміни менше, ніж значень для пошуку, то в якості
нових значень використовується порожній рядок.

Приклад. Використання функції str_replace(). Варіант 2


55

<?php
$greeting = array("Привіт", "Привіт всім!",
"Привіт, друзі!","Здрастуйте", "Hi");
// об'єкт
$search = array ("Привіт", "Здрастуйте", "Hi");
// значення, які будемо заміняти
$replace = array ("Добрий ранок", "День добрий");
// значення, якими будемо заміняти
$new_greet = str_replace($search, $replace, $greeting);
// робимо заміну
print_r($new_greet);
//виводимо отриманий масив
?>

У результаті одержимо такий масив:

Array ([0] => Добрий ранок [1] => Добрий ранок всім!
[2] => Добрий ранок, друзі! [3] => День добрий [4] =>)

Якщо значення для пошуку - масив, а значення для заміни - рядок, то


цей рядок буде використаний для заміни всіх знайдених значень.

Приклад. Використання функції str_replace(). Варіант 3

<?php
$greeting = array("Привіт", "Привіт всім!",
"Привіт, друзі!", "Здрастуйте");
// об'єкт
$search = array ("Привіт","Здрастуйте");
// значення, які будемо заміняти
$replace = "День добрий";
// значення, яким будемо заміняти
$new_greet = str_replace($search, $replace, $greeting);
// робимо заміну
print_r($new_greet);
//виводимо отриманий масив
?>

Одержимо:

Array ([0] => День добрий [1] => День добрий всім! [2]
=> День добрий, друзі!
[3] => День добрий)
56

Функція str_replace() чутлива до регістра, але існує її


регістронезалежний аналог - функція str_ireplace(). Однак ця функція
підтримується не у всіх версіях PHP.
Функція substr_replace

Ця функція сполучає в собі властивості двох уже розглянутих нами


функцій - функції str_replace() і substr(). Її синтаксис такий:

substr_replace (вихідний рядок, рядок для заміни,


позиція початкового символу [, довжина])

Ця функція заміняє частину рядка рядком, призначеним для заміни.


Заміняється та частина рядка, що починається з позиції, зазначеної
параметром позиція початкового символу. За допомогою
додаткового аргументу довжина можна обмежити число замінних символів.
Тобто, фактично, ми не вказуємо конкретно рядок, який потрібно замінити,
ми тільки описуємо, де він перебуває й, можливо, яку довжину має. У цьому
відмінність функції substr_replace() від str_replace().
Як й у випадку з функцією substr() аргументи позиція
початкового символу й довжина можуть бути негативними. Якщо
позиція початкового символу негативна, то заміна здійснюється, починаючи
з цієї позиції до кінця рядка. Негативна довжина задає, скільки символів від
кінця рядка не повинно бути замінено. Якщо довжина не вказується, то
заміна відбувається до кінця рядка.

Приклад. Використання функції substr_replace()

<?php
$text = "Мене кличуть Андрій.";
echo "Вихідний рядок: $text<hr>";
/* Наступні два рядки замінять
вихідний рядок рядком 'А мене - Олексій' */
echo substr_replace($text, 'А мене - Олексій', 0) .
"<br>\n";
echo substr_replace($text, 'А мене - Олексій', 0,
strlen($text)) . "<br>\n";
// Наступний рядок додасть слово 'Привіт! '
// у початок вихідного рядка
echo substr_replace($text, 'Привіт! ', 0, 0) .
"<br>\n";
?>

У результаті роботи цього скрипта одержимо:


57

Вихідний рядок: Мене кличуть Андрій.


-----------------------------------
А мене - Олексій
А мене - Олексій
Привіт! Мене кличуть Андрій.

5.4 Поділ і з'єднання рядка

Дуже корисні функції - функція поділу рядка на частини й зворотна їй


функція об'єднання рядків в один рядок. Чому дуже корисні? Наприклад,
якщо ви динамічно генеруєте форму за бажанням користувача, можна
запропонувати йому вводити елементи для створення списку вибору,
розділяючи їх яким-небудь символом. І для того щоб обробити отриманий
список значень, саме й пригодиться вміння розбивати рядок на частини. Для
реалізації такої розбивки в PHP можна використати функцію:

explode(роздільник,вихідний рядок [,максимальне


число елементів])

Функція explode() ділить вихідний рядок на підрядки, кожний з


яких відділений від сусіднього за допомогою зазначеного роздільника, і
повертає масив отриманих рядків. Якщо задано додатковий параметр
максимальне число елементів, то число елементів у масиві буде не більше
цього параметра, в останній елемент записується весь залишок рядка. Якщо в
якості роздільника зазначений порожній рядок "", то функція explode()
поверне false. Якщо символа роздільника у вихідному рядку немає, то
повертається вихідний рядок без змін.

Приклад. Ми хочемо створити елемент форми - список, що випадає, і


значення для цього списку повинен ввести користувач, не знайомий з мовою
html. Створимо таку форму:

<form action="exp.php">
Введіть варіанти для вибору автора статті
через двокрапку (":"):<br>
<input type="text" name="author" size=40>
<br>
<input type="submit" value="Створити елемент">
</form>

Скрипт, що буде її обробляти (exp.php), може бути таким:

<?php
58

$str = $_GET["author"];
$names = explode(":",$str);
// розбиваємо рядок, введений користувачем за
допомогою ":"
$s = "<select name=’author’>";
// створюємо список, що випадає
foreach ($names as $k => $name) {
$s .= "<option value=$k>$name";
// додаємо елементи до списку
}
$s .= "</select>";
echo $s;
?>

Крім поділу рядка на частини іноді, навпаки, виникає необхідність


об'єднання декількох рядків в одне ціле. Функція, запропонована для цього
мовою PHP, називається implode():

implode (string $glue , array $pieces)

Ця функція поєднує елементи масиву за допомогою переданого їй


об'єднуючого елемента (наприклад, коми). На відміну від функції
explode(), порядок аргументів у функції implode() не має значення.
Приклад. Припустимо, ми зберігаємо ім'я, прізвище й по-батькові
людини окремо, а виводити їх на сторінці потрібно разом. Щоб з'єднати їх в
один рядок, можна використати функцію implode():

<?php
$data = array("Ткаченко","Іван","Борисович");
$str = implode(" ", $data);
echo $str;
?>

У результаті роботи цього скрипта одержимо рядок:

Ткаченко Іван Борисович

У функції implode() існує псевдонім - функція join(), тобто ці дві


функції відрізняються лише іменами.

5.5 Рядки, що містять html-код

Досить часто ми працюємо з рядками, що містять html-теги. Якщо


відобразити такий рядок у браузер за допомогою звичайних функцій
59

відображення даних echo() або print(), то ми не побачимо самих html-


тегів, а одержимо відформатований відповідно до цих тегів рядок. Браузери
обробляють всі html-теги у відповідності зі стандартом мови HTML. Іноді
нам потрібно бачити безпосередньо рядок, без обробки її браузером. Щоб
цього домогтися, потрібно перед тим, як виводити рядок, застосувати до
нього функцію htmlspecialchars().
Функция htmlspecialchars (рядок [, стиль лапок [,
кодування]]) переводить спеціальні символи, такі як «<», «>», «&», «"» ,
«'» у такі сутності мови HTML, як «&lt;», «&gt;», «&amp;», «&quot;»,
«&#039;» відповідно.
Додатковий аргумент стиль лапок визначає, як повинні
інтерпретуватися подвійні й одинарні лапки. Він може мати одне з трьох
значень: ENT_COMPAT, ENT_QUOTES, ENT_NOQUOTES. Константа
ENT_COMPAT означає, що подвійні лапки повинні бути переведені в
спецсимволи, а одинарні повинні залишитися без змін. ENT_QUOTES
говорить, що повинні конвертуватися й подвійні й одинарні лапки, а
ENT_NOQUOTES залишає й ті й інші лапки без змін.
У параметрі кодування можуть бути задані такі кодування, як UTF-8,
ISO-8859-1 й інші.

Приклад. Використання функції htmlspecialchars()

<?php
$new = htmlspecialchars("<a href='mailto:au@ukr.net'>
Написати лист</a>", ENT_QUOTES);
echo $new;

/* наш рядок перекодується в такий:


&lt;a href=&#039;mailto:au@ukr.net &#039;&gt;
Написати лист&lt;/a&gt; */
?>

У браузері ми побачимо:

<a href='mailto:au@ukr.net '>Написати лист</a>

Функція htmlspecialchars() перекодує тільки найбільш часто


використовувані спецсимволи. Якщо необхідно конвертувати всі символи в
сутності HTML, варто задіяти функцію htmlentities().
60

6 ВЗАЄМОДІЯ PHP Й MYSQL

У цьому розділі розглядаються способи взаємодії PHP і СУБД MySql.


Основна увага приділяється установці з'єднання з базою даних, функціям
відправлення запитів й обробці відповідей (mysql_connect,
mysql_query, mysql_result, mysql_num_rows, mysql_close).
Наводиться приклад - створення web -інтерфейсу для адміністрування бази
даних віртуального музею історії.
У дистрибутив PHP входить розширення, що містить вбудовані функції
для роботи з базою даних MySQL. Ми познайомимося з деякими основними
функціями для роботи з MySQL, які будуть потрібні для рішення завдань
побудови web-інтерфейсів з метою відображення й наповнення бази даних.
Виникає питання, навіщо будувати такі інтерфейси? Для того щоб вносити
інформацію в базу даних і переглядати її вміст могли люди, не знайомі з
мовою запитів SQL. При роботі з web-інтерфейсом для додавання інформації
в базу даних людині потрібно просто ввести ці дані в html-форму й
відправити їх на сервер, а наш скрипт зробить все інше. А для перегляду
вмісту таблиць досить просто клацнути по посиланню й зайти на потрібну
сторінку.
Для наочності будемо будувати ці інтерфейси для таблиці Artifacts, у
якій міститься інформація про експонати віртуального музею інформатики.
Кожен експонат у колекції Artifacts описується за допомогою наступних
характеристик:
 назва (title);
 автор (author);
 опис (description);
 альтернативна назва (alternative);
 зображення (photo).
Назва й альтернативна назва є рядками менш ніж 255 символів
довжиною (тобто мають тип VARCHAR(255)), опис - текстове поле (має тип
TEXT), а в полях "автор" й "зображення" утримуються ідентифікатори автора
з колекції опису персон Persons і зображення експоната з колекції зображень
Images відповідно.

Побудова інтерфейсу для додавання інформації

Отже, у нас є якась таблиця в базі даних. Щоб побудувати інтерфейс


для додавання інформації в цю таблицю, потрібно її структуру (тобто набір її
полів) відобразити в html-форму.
Розіб'ємо це завдання на наступні підзадачі:
 установка з'єднання з БД;
 вибір робочої БД;
 одержання списку полів таблиці;
 відображення полів в html-форму.
61

Після цього дані, введені у форму, потрібно записати в базу даних.


Розглянемо всі ці завдання по порядку.

6.1 Установка з'єднання

Отже, перше, що потрібно зробити, - це встановити з'єднання з базою


даних. Скористаємося функцією mysql_connect.
Синтаксис mysql_connect:

ресурс mysql_connect ([рядок server [, рядок username


[, рядок password
[, логічне new_link [, ціле client_flags]]]]])

Дана функція встановлює з'єднання з сервером MySQL і повертає


покажчик на це з'єднання або FALSE у випадку невдачі. Для відсутніх
параметрів установлюються наступні значення за замовчуванням:

server = 'localhost:3306'
username = ім'я користувача власника процесу сервера
password = порожній пароль

Якщо функція викликається двічі з тими самими параметрами, то нове


з'єднання не встановлюється, а повертається посилання на старе з'єднання.
Щоб цього уникнути, використовують параметр new_link, що змушує в
кожному разі відкрити ще одне з'єднання.
Параметр client_flags - це комбінація наступних констант:
MYSQL_CLIENT_COMPRESS (використати протокол стиску),
MYSQL_CLIENT_IGNORE_SPACE (дозволяє вставляти пробіли після
імен функцій), MYSQL_CLIENT_INTERACTIVE (чекати
interactive_timeout секунд - замість wait_timeout - до закриття
з'єднання).
Параметр new_link з'явився в PHP 4.2.0, а параметр client_flags
- в PHP 4.3.0.
З'єднання з сервером закривається при завершенні виконання скрипта,
якщо воно до цього не було закрито за допомогою функції mysql_close().
Отже, встановлюємо з'єднання з базою даних на локальному сервері
для користувача nina з паролем "123":

<?php
$conn = mysql_connect("localhost", "nina","123")
or die("Неможливо встановити з'єднання:
".mysql_error());
echo "З'єднання встановлене";
mysql_close($conn);?>
62

6.2 Вибір бази даних

Після установки з'єднання потрібно вибрати базу даних, з якою будемо


працювати. Наші дані зберігаються в базі даних book. В MySQL вибір бази
даних здійснюється за допомогою команди use:

mysql>use book;

В PHP для цього існує функція mysql_select_db.


Синтаксис mysql_select_db:

логічне mysql_select_db (рядок database_name [, ресурс


link_identifier])

Ця функція повертає TRUE у випадку успішного вибору бази даних й


FALSE - у противному випадку.
Зробимо базу даних book робочою:

<?php
$conn = mysql_connect("localhost","nina","123")
or die("Неможливо встановити
з'єднання: ".mysql_error());
echo "З'єднання встановлене";
mysql_select_db("book");
?>

6.3 Одержання списку полів таблиці

Тепер можна зайнятися властиво рішенням задачі. Як одержати список


полів таблиці? Дуже просто. В PHP і на цей випадок є своя команда -
mysql_list_fields.
Синтаксис mysql_list_fields:

ресурс mysql_list_fields (рядок database_name,


рядок table_name [, ресурс link_identifier])

Ця функція повертає список полів у таблиці table_name у базі даних


database_name. Виходить, що вибирати базу даних нам було
необов'язково, але це пригодиться пізніше. Як можна помітити, результат
роботи цієї функції - змінна типу ресурс. Тобто це не зовсім те, що ми хотіли
одержати. Це посилання, яке можна використати для одержання інформації
про поля таблиці, включаючи їхні назви, типи й прапори.
Функція mysql_field_name повертає ім'я поля, отриманого в
результаті виконання запиту. Функція mysql_field_len повертає
63

довжину поля. Функція mysql_field_type повертає тип поля, а функція


mysql_field_flags повертає список прапорів поля, записаних через
пробіл. Типи поля можуть бути int, real, string, blob і т.д.
Прапори можуть бути not_null, primary_key, unique_key,
blob, auto_increment і т.д.
Синтаксис у всіх цих команд однаковий:

рядок mysql_field_name (ресурс result, ціле


field_offset)
рядок mysql_field_type (ресурс result, ціле
field_offset)
рядок mysql_field_flags (ресурс result, ціле
field_offset)
рядок mysql_field_len (ресурс result, ціле
field_offset)

Тут result - це ідентифікатор результату запиту (наприклад, запиту,


відправленого функціями mysql_list_fields або mysql_query (про
неї буде розказано пізніше)), а field_offset - порядковий номер поля в
результаті.
Загалом кажучи, те, що повертають функції типу
mysql_list_fields або mysql_query, являє собою таблицю, а точніше,
покажчик на неї. Щоб одержати з цієї таблиці конкретні значення, потрібно
задіяти спеціальні функції, які построчно читають цю таблицю. До таких
функцій і належать mysql_field_name і т.п. Щоб перебрати всі рядки в
таблиці результату виконання запиту, потрібно знати число рядків у цій
таблиці. Команда mysql_num_rows(ресурс result) повертає число
рядків у безлічі результатів result.
А тепер спробуємо одержати список полів таблиці Artifacts (колекція
експонатів).

<?php
$conn = mysql_connect("localhost","nina","123")
or die("Неможливо встановити
з'єднання: ".mysql_error());
echo "З'єднання встановлене";
mysql_select_db("book");
$list_f = mysql_list_fields("book","Artifacts",$conn);
$n = mysql_num_fields($list_f);
for($i=0;$i<$n; $i++){
$type = mysql_field_type($list_f, $i);
$name_f = mysql_field_name($list_f,$i);
$len = mysql_field_len($list_f, $i);
$flags_str = mysql_field_flags($list_f, $i);
64

echo "<br>Ім'я поля: ".$name_f;


echo "<br>Тип поля: ".$type;
echo "<br>Довжина поля: ".$len;
echo "<br>Рядок прапорів поля: ".$flags_str."<hr>";
}
?>

У результаті повинно вийти приблизно от що (якщо в таблиці всього


два поля, звичайно):

Ім'я поля: id
Тип поля: int
Довжина поля: 11
Рядок прапорів поля:
not_null primary_key auto_increment
_________________________________________________
Ім'я поля: title
Тип поля: string
Довжина поля: 255
Рядок прапорів поля:

6.4 Відображення списку полів в html-форму

Тепер трошки підкоригуємо попередній приклад. Будемо не просто


виводити інформацію про поле, а відображати його в найбільш прийнятний
елемент html-форми. Так, елементи типу BLOB переведемо в textarea
(помітимо, що поле description, що ми створювали з типом TEXT,
відображається як таке, що має тип BLOB), числа й рядки відобразимо в
текстові рядки введення <input type="text">, а елемент, що має мітку
автоінкремента, взагалі не будемо відображати, оскільки його значення
встановлюється автоматично.
Все це вирішується досить просто, за винятком виділення зі списку
прапорів прапора auto_increment. Для цього потрібно скористатися
функцією explode.
Синтаксис explode:

масив explode(рядок separator, рядок string [, int


limit])

Ця функція розбиває рядок string на частини за допомогою


роздільника separator і повертає масив отриманих рядків.
У нашому випадку як роздільник потрібно взяти пробіл " ", а як
вихідний рядок для розбивки - рядок прапорів поля.
Отже, створимо форму для введення даних у таблицю Artifacts:
65

<?php
$conn=mysql_connect("localhost","nina","123");
// установлюємо з'єднання
$database = "book";
$table_name = "Artifacts";
mysql_select_db($database); // вибираємо базу даних для
роботи
$list_f = mysql_list_fields($database,$table_name);
// одержуємо список полів у таблиці
$n = mysql_num_fields($list_f); // число рядків у
результаті
// попереднього запиту (тобто скільки всього
// полів у таблиці Artifacts)
echo "<form method=post action=insert.php>";
// створюємо форму для уведення даних
echo "&nbsp;<TABLE BORDER=0 CELLSPACING=0 width=50%
><tr>
<TD BGCOLOR='#005533' align=center><font
color='#FFFFFF'>
<b> Add new row in
$table_name</b></font></td></tr><tr><td></td></tr></TAB
LE>";
echo "<table border=0 CELLSPACING=1 cellpadding=0
width=50% >";
// для кожного поля одержуємо його ім'я, тип, довжину й
прапори
for($i=0;$i<$n; $i++){
$type = mysql_field_type($list_f, $i);
$name_f = mysql_field_name ($list_f,$i);
$len = mysql_field_len($list_f, $i);
$flags_str = mysql_field_flags ($list_f, $i);
// з рядка прапорів робимо масив,
// де кожен елемент масиву - прапор поля
$flags = explode(" ", $flags_str);
foreach ($flags as $f){
if ($f == 'auto_increment') $key = $name_f;
// запам'ятовуємо ім'я автоінкремента
}
/* для кожного поля, що не є автоінкрементом, в
залежності від його типу виводимо підходящий елемент
форми */
if ($key <> $name_f){
echo "<tr><td align=right bgcolor='#C2E3B6'><font
size=2>
66

<b>&nbsp;".$name_f."</b></font></td>";
switch ($type){
case "string":
$w = $len/5;
echo "<td><input type=text name=\"$name_f\"
size = $w ></td>";
break;
case "int":
$w = $len/4;
echo "<td><input type=text name=\"$name_f\"
size = $w ></td>";
break;
case "blob":
echo "<td><textarea rows=6 cols=60
name=\"$name_f\"></textarea></td>";
break;
}
}
echo "</tr>";
}
echo "</table>";
echo "<input type=submit name='add' value='Add'>";
echo "</form>";
?>

6.5 Запис даних у базу даних

Отже, форма створена. Тепер потрібно зробити саме головне -


відправити дані з цієї форми в нашу базу даних. Для того щоб записати дані в
таблицю, використовується команда INSERT мови SQL. Наприклад:

mysql> INSERT INTO Artifacts SET title='Петров';

Виникає питання, як можна скористатися такою командою (або будь-


якою іншою командою SQL) в PHP скрипті. Для цього існує функція
mysql_query().
Синтаксис mysql_query:

ресурс mysql_query (рядок query [, ресурс


link_identifier])

mysql_query() посилає SQL-запит активній базі даних MySQL


сервера, що визначається за допомогою покажчика link_identifier (це
посилання на якесь з'єднання з сервером MySQL). Якщо параметр
link_identifier опущений, використовується останнє відкрите
67

з'єднання. Якщо відкриті з'єднання відсутні, функція намагається з'єднатися з


СУБД, аналогічно функції mysql_connect() без параметрів. Результат
запиту буферизується.
Рядок запиту не повинен закінчуватися крапкою з комою.
Тільки для запитів SELECT, SHOW, EXPLAIN, DESCRIBE,
mysql_query() повертає покажчик на результат запиту, або FALSE, якщо
запит не був виконаний. В інших випадках mysql_query() повертає
TRUE, якщо запит виконаний успішно, і FALSE - у випадку помилки.
Значення, не рівне FALSE, говорить про те, що запит був виконаний
успішно. Воно не говорить про кількість повернутих рядів. Функція
mysql_query() також вважається помилковою і поверне FALSE, якщо в
користувача недостатньо прав для роботи з зазначеною в запиті таблицею.
Отже, тепер ми знаємо, як відправити запит на вставку рядків у базу
даних. Помітимо, що в попередньому прикладі елементи форми ми назвали
іменами полів таблиці. Тому вони будуть доступні в скрипті insert.php,
що обробляє дані форми, як змінні виду $_POST['ім'я_поля'].

<?php
$conn=mysql_connect("localhost","nina","123");//
установлюємо з'єднання
$database = "book";
$table_name = "Artifacts";
mysql_select_db($database); // вибираємо базу даних
$list_f = mysql_list_fields($database,$table_name);
// одержуємо список полів у таблиці
$n = mysql_num_fields($list_f); // число рядків у
результаті
// попереднього запиту
// складемо один запит відразу для всіх полів таблиці
$sql = "INSERT INTO $table_name SET "; // починаємо
створювати
// запит, перебираємо всі поля таблиці
for($i=1;$i<$n; $i++){
$name_f = mysql_field_name ($list_f,$i); //
обчислюємо імена поля
$value = $_POST[$name_f]; // обчислюємо значення
поля
$j = $i + 1;
$sql = $sql.$name_f." = '$value'"; // дописуємо в
// рядок $sql пари ім'я=значення
if ($j <> $n) $sql = $sql.", "; // якщо поле не
// останнє в списку, то ставимо кому
}
// перед тим як записувати щось у базу,
68

// можна подивитися, який запит вийшов


//echo $sql;
$result = mysql_query($sql,$conn); // відправляємо
запит
// виводимо повідомлення чи успішно виконано
запит
if (!$result) echo " Can't add ($table_name) ";
else echo "Success!<br>";
?>

Отже, завдання додавання даних за допомогою web-інтерфейсу ми


вирішили. Далі ми звернемося до іншого завдання - відображення даних, що
зберігаються в базі даних СУБД MySQL.

6.6 Відображення даних, що зберігаються в MySQL

Щоб відобразити якісь дані в браузер за допомогою PHP, потрібно


спочатку одержати ці дані у вигляді змінних PHP. При роботі з MySQL без
посередника (такого, як PHP) вибірка даних здійснюється за допомогою
команди SELECT мови SQL:

mysql> SELECT * FROM Artifacts;

Раніше ми говорили, що будь-який запит, у тому числі й на вибірку,


можна відправити на сервер за допомогою функції mysql_query(). Там у
нас стояла трохи інша задача - одержати дані з форми й відправити їх за
допомогою запиту на вставку в базу даних. Результатом роботи
mysql_query() там міг бути тільки один з виразів, TRUE або FALSE.
Тепер же потрібно відправити запит на вибір всіх полів, а результат
відобразити в браузері. І тут результат - це ціла таблиця значень, а точніше,
покажчик на цю таблицю. Так що потрібні якісь аналоги функції
mysql_field_name(), тільки щоб вони витягали з результату запиту не
ім'я, а значення поля. Таких функцій в PHP кілька. Найбільш популярні -
mysql_result() і mysql_fetch_array().
Синтаксис mysql_result:

змішане mysql_result (ресурс result, ціле row [,


змішане field])

mysql_result() повертає значення одного осередку результату


запиту. Аргумент field може бути порядковим номером поля в результаті,
ім'ям поля або ім'ям поля з ім'ям таблиці через крапку
tablename.fieldname. Якщо для імені поля в запиті застосовувався аліас
69

('select foo as bar from...'), використовуйте його замість


реального імені поля.
Працюючи з великими результатами запитів, варто задіяти одну з
функцій, що обробляють відразу цілий ряд результату (наприклад,
mysql_fetch_row(), mysql_fetch_array() і т.д.). Тому що ці
функції повертають значення декількох осередків відразу, вони набагато
швидше mysql_result(). Крім того, потрібно врахувати, що вказівка
чисельного зсуву (номера поля) працює набагато швидше, ніж вказівка
колонки або колонки й таблиці через крапку.
Виклики функції mysql_result() не повинні змішуватися з іншими
функціями, що працюють з результатом запиту.
Синтаксис mysql_fetch_array:

масив mysql_fetch_array (ресурс result [, ціле


result_type])

Ця функція обробляє ряд результату запиту, повертаючи масив


(асоціативний, чисельний або обоє) з обробленим рядом результату запиту,
або FALSE, якщо рядів більше немає.
mysql_fetch_array() - це розширена версія функції
mysql_fetch_row(). Крім зберігання значень у масиві із чисельними
індексами, функція повертає значення в масиві з індексами за назвою
колонок.
Якщо кілька колонок у результаті будуть мати однакові назви, буде
повернута остання колонка. Щоб одержати доступ до перших, варто
використати чисельні індекси масиву або аліаси в запиті. У випадку аліасов
ви не зможете використати дійсні імена колонок, як, наприклад, не зможете
використати "photo" в описаному нижче прикладі.

Приклад. Запит з іменами колонок, що дублюються.

select Artifacts.photo as art_image,


Persons.photo as pers_image
from Artifacts, Persons

Важливо помітити, що mysql_fetch_array() працює не


повільніше, ніж mysql_fetch_row(), і надає більш зручний доступ до
даних.
Другий опціональний аргумент result_type у функції
mysql_fetch_array() є константою й може приймати наступні
значення: MYSQL_ASSOC, MYSQL_NUM й MYSQL_BOTH. Ця можливість
додана в PHP 3.0.7. Значенням за замовчуванням є: MYSQL_BOTH.
Використовуючи MYSQL_BOTH, одержимо масив, що складається як з
асоціативних індексів, так і із чисельних. MYSQL_ASSOC поверне тільки
70

асоціативні відповідності, а MYSQL_NUM - тільки чисельні. Імена полів, що


повертаються цією функцією, регістрозалежні.
Тепер відобразимо дані з Artifacts у вигляді таблиці в браузері:

<?php
/ * спочатку робимо те ж, що й раніше: установлюємо
з'єднання, вибираємо базу й одержуємо список і число
полів у таблиці Artifacts */
$conn=mysql_connect("localhost","nina","123");
$database = "book";
$table_name = "Artifacts";
mysql_select_db($database);
$list_f = mysql_list_fields($database,$table_name);
$n1 = mysql_num_fields($list_f);
// збережемо імена полів у масиві $names
for($j=0;$j<$n1; $j++){
$names[] = mysql_field_name ($list_f,$j);
}
$sql = "SELECT * FROM $table_name"; // створюємо SQL
запит
$q = mysql_query($sql,$conn) or die(); // відправляємо
// запит на сервер
$n = mysql_num_rows($q); // одержуємо число рядків
результату
//малюємо HTML-таблицю
echo "&nbsp;<TABLE BORDER=0 CELLSPACING=0 width=90%
align=center><tr><TD BGCOLOR='#005533'
align=center>
<font
color='#FFFFFF'><b>$table_name</b></font></td>
</tr></TABLE>";
echo "<table cellspacing=0 cellpadding=1 border=1
width=90% align=center>";
// відображаємо назви полів
echo "<tr>";
foreach ($names as $val){
echo "<th ALIGN=CENTER BGCOLOR='#C2E3B6'>
<font size=2>$val</font></th>";
}
// відображаємо значення полів
echo "</tr>";
for($i=0;$i<$n; $i++){ // перебираємо всі рядки в
// результаті запиту на вибірку
echo "<tr>";
foreach ($names as $val) { // перебираємо всі
71

// імена полів
$value = mysql_result($q,$i,$val); // одержуємо
// значення поля
echo "<td><font
size=2>&nbsp;$value</font></td>";
// виводимо значення поля
}
echo "</tr>";
}
echo "</table>";
?>

Зробимо те ж саме за допомогою mysql_fetch_array():

<?php
/* ... початок те ж, що й у попередньому прикладі */
// відображаємо значення полів
// одержуємо значення поля у вигляді асоціативного
масиву
while($row = mysql_fetch_array($q, MYSQL_ASSOC)) {
echo "<tr>";
foreach ($names as $val){
echo "<td><font
size=2>&nbsp;$row[$val]</font></td>";
// виводимо значення поля
}
echo "</tr>";
}
echo "</table>";
?>

Ми вирішили дві задачі: додавання даних у базу даних й їхнє


відображення в браузері за допомогою мови PHP. Для цього ми розглянули
ряд функцій, які дозволяють відправляти SQL-запити до бази даних й
обробляти отримані відповіді. Використовуючи наведену тут технологію,
можна вирішити цілий ряд схожих задач, таких як задача зміни й видалення
даних, задача маніпулювання таблицями бази даних (тобто їхнє створення,
зміна й видалення) і т.п. Все це типові задачі, що виникають при розробці
систем керування даними, і вміння їх вирішувати, як й уміння працювати з
базами даних у цілому, дуже важливо для web-програміста.
72

7 АВТОРИЗАЦІЯ ДОСТУПУ ЗА ДОПОМОГОЮ СЕСІЙ

Розділ присвячений вивченню питань забезпечення безпеки в мережі й


використанню для цих цілей механізму сесій. Розглядаються: ініціалізація
сесій, передача ідентифікатора користувача, реєстрація змінних сесії,
знищення сесії. Також розглядається настроювання сесій у файлах php.ini,
httpd.conf. У завершення наводиться приклад авторизації користувача за
допомогою механізму сесій.

7.1 Авторизація доступу

Що таке авторизація доступу? Спробуємо пояснити на прикладі зі


звичайного життя. Ви хочете взяти в бібліотеці книгу. Але ця послуга
доступна тільки тим, у кого є читацький квиток. Можна сказати, що за
допомогою цього квитка здійснюється "авторизація доступу" до бібліотечних
ресурсів. Бібліотекар після пред'явлення йому читацького квитка знає, хто
бере книгу, і якщо буде потреба (наприклад, книгу довго не повертають)
може вжити заходів (подзвонити боржникові додому). Бібліотекар має
набагато більше прав, ніж звичайний відвідувач: він може давати або не
давати книги певному відвідувачеві, може виставляти напоказ новинки й
забирати в архів книги, що читають рідко, і т.п.
В інформаційних технологіях все приблизно так само. У мережі існує
величезна кількість ресурсів, тобто безліч "бібліотек". У кожної з них свій
"бібліотекар", тобто людина або група людей, відповідальних за зміст
ресурсу й надання користувачам інформації. Їх називають адміністраторами.
Функції адміністратора, як правило, включають додавання нової інформації,
видалення й редагування існуючої, настроювання способів відображення
інформації користувачеві. А у функції користувача (простого відвідувача
ресурсу) входить тільки пошук і перегляд інформації.
Як же відрізнити користувача від адміністратора? У реальній бібліотеці
це якось очевидно, але якщо ролі бібліотекаря й відвідувача бібліотеки
перенести у віртуальну реальність, то ця очевидність зникає. Бібліотекар, як і
відвідувач, має доступ до бібліотечних ресурсів через Internet. А відповідно
до протоколу HTTP всі клієнти абсолютно рівноправні. Як же зрозуміти, хто
зайшов на сайт? Звичайний користувач (відвідувач) або адміністратор
(бібліотекар)? Якщо це простий користувач, то як зберегти це знання, щоб не
допустити відвідувача в закриті архіви сайту? Тобто виникає питання, як
ідентифікувати клієнта, що надіслав запит, і зберігати відомості про нього,
поки він перебуває на сайті?
Найпростіший варіант, що спадає на думку, - це реєстрація людини в
системі й видача йому аналога читацького квитка, а саме логіна й пароля для
входу в адміністративну частину системи. Ця інформація зберігається на
комп'ютері-сервері, і при вході в систему перевіряється відповідність
введених користувачем логіна й пароля тим, що зберігаються в системі.
Правда, тут у порівнянні з реальною бібліотекою ситуація змінюється:
73

читацький квиток потрібно бібліотекареві для входу в закриту частину


системи, а читач може заходити на сайт вільно. У принципі можна
реєструвати й простих відвідувачів. Тоді всіх зареєстрованих користувачів
потрібно розділити на групи: бібліотекарі (адміністратори) і читачі (прості
користувачі), наділивши їх відповідними правами. Ми не будемо вдаватися в
ці тонкості й скористаємося найпростішим варіантом, коли введення логіна й
пароля потрібно для доступу до деяких сторінок сайту.

Приклад. У нас є файл index.html - домашня сторінка Андрія Петрова

<html>
<head><title>My home page</title></head>
<body>
Привіт всім! Мене кличуть Андрій Петров й це моя
домашня сторінка.
<a href="secret_info.html">Для Петра</a>
</body>
</html>

і файл secret_info.html, що містить секретну інформацію, читати яку


дозволено тільки другові Андрія Петру.

<html>
<head><title>Secret info</title></head>
<body>
<p>Тут я хочу ділитися секретами з другом Петром.</p>
</body>
</html>

Якщо залишити обоє ці файли як є, то будь-який відвідувач, кликнувши


на посилання "Для Петра", потрапить на секретну сторінку. Щоб цього
уникнути, потрібно додати проміжний скрипт, що буде перевіряти, чи дійсно
Петро хоче потрапити на секретну сторінку. І зробити так, щоб головний
файл посилався не відразу на secret_info.html, а спочатку на цей
скрипт. Змінимо файл index.html.

<html>
<head><title>My home page</title></head>
<body>
<p>Привіт всім! Мене кличуть Андрій Петров й це моя
домашня сторінка.
</p>
<a href="authorize.php">Для Петра</a>
</body>
74

</html>

Сам скрипт авторизації повинен надавати форму для введення логіна й


пароля, перевіряти їхню правильність і перенаправляти на секретну сторінку,
якщо перевірка пройшла успішно, і видавати повідомлення про помилку в
противному випадку. Код скрипта у файлі authorize.php наведений
нижче.

<?php
if (!isset($_GET['go'])){
// перевіряємо, чи відправлені дані формою
// форма для авторизації (введення логіна й пароля)
echo "<form>
Login: <input type='text' name='login'>
Password: <input type='password' name='passwd'>
<input type='submit' name='go' value='Go'>
</form>";
}else {
// якщо форма заповнена, то порівнюємо логін
// і пароль із правильними логіном і паролем
if ($_GET['login']=="pit" &&
$_GET['passwd']=="123") {
Header("Location: secret_info.html");
//і перенаправляємо на секретну сторінку
}else echo "Невірне введення,
спробуйте ще раз<br>";
}
?>

Начебто б все достаточно просто. Але припустимо, у нас не одна


секретна сторінка, а кілька. Причому вони зв'язані між собою перехресними
посиланнями. Тоді виникає необхідність постійно пам'ятати пароль і логін
відвідувача сайту. Щоб вирішити цю проблему, можна в кожну сторінку
вмонтувати скрипт, що буде передавати логін і пароль від сторінки до
сторінки як сховані параметри форми. Але такий спосіб не зовсім безпечний:
ці параметри можна перехопити й підробити. В PHP існує більш зручний і
безпечний метод рішення проблеми зберігання даних про відвідувача
протягом сеансу його роботи із сайтом - це механізм сесій.

7.2 Механізм сесій

Cесії - це механізм, що дозволяє створювати й використовувати змінні,


що зберігають своє значення протягом усього часу роботи користувача з
сайтом.
75

Ці змінні для кожного користувача мають різні значення й можуть


використатися на будь-якій сторінці сайту до виходу користувача з системи.
При цьому щораз, заходячи на сайт, користувач одержує нові значення
змінних, що дозволяють ідентифікувати його протягом цього сеансу або сесії
роботи з сайтом. Звідси й назва механізму - сесії.
Завдання ідентифікації користувача вирішується шляхом присвоєння
кожному користувачеві унікального номера, так називаного ідентифікатора
сесії (SID, Session IDentifier). Він генерується PHP у той момент, коли
користувач заходить на сайт, і знищується, коли користувач іде з сайту, і
являє собою рядок з 32 символів (наприклад,
ac4f4a45bdc893434c95dcaffb1c1811). Цей ідентифікатор передається на
сервер разом з кожним запитом клієнта й повертається назад разом з
відповіддю сервера.
Існує кілька способів передачі ідентифікатора сесії:
 За допомогою cookies.
Cookies були створені спеціально як метод однозначної ідентифікації
клієнтів й являють собою розширення протоколу HTTP. У цьому
випадку ідентифікатор сесії зберігається в тимчасовому файлі на
комп'ютері клієнта, що послав запит. Метод, безсумнівно, гарний, але
багато користувачів відключають підтримку cookies на своєму
комп'ютері через проблеми з безпекою.
 За допомогою параметрів адресного рядка.
У цьому випадку ідентифікатор сесії автоматично вбудовується в усі
запити (URL), передані серверу, і зберігається на стороні сервера.
Наприклад: адреса http://example.com/test.php
перетворюється на адресу

http:// example.com/test.php?PHPSESSID=
c4f4a45bdc893434c95dcaffb1c1811

Цей спосіб передачі ідентифікатора використовується автоматично,


якщо в браузера, що відправив запит, виключені cookies. Він досить надійний
- передавати параметри в адресному рядку можна завжди. З іншого боку,
ідентифікатор сесії можна підглянути, скористатися збереженим варіантом у
рядку браузера або підробити. Хоча, звичайно, всі ці проблеми або надумані
або їх можна вирішити. Наприклад, хто зможе запам'ятати рядок з 32 різних
символів? А якщо правильно організувати роботу з сесіями (вчасно їх
знищувати), то навіть збережений у браузері номер сесії нічого не дасть.

7.3 Настроювання сесій

Перш ніж почати працювати з сесіями, варто розібратися в тому, як


коректно налаштовувати їхню обробку інтерпретатором PHP. Сама робота з
сесіями в PHP підтримується за замовчуванням. Це значить, що
76

встановлювати ніяких додаткових елементів не потрібно. А от знати, що


записано в настроюваннях цього модуля, корисно, щоб уникнути помилок
при роботі з ним.
Настроювання PHP, у тому числі й для роботи з сесіями, прописуються
у файлі php.ini. Звернемося до цього файлу.
Як ми вже знаємо, ідентифікатор сесії (число, по якому можна
унікально ідентифікувати клієнта, що послав запит) зберігається або на
комп'ютері-сервері, або на комп'ютері-клієнті, або й там, і там.
Параметр session.save_path в php.ini, визначає, де на сервері
будуть зберігатися дані сесії. Із-за нього найчастіше виникають проблеми для
Windows-серверів, тому що за замовчуванням значення
session.save_path установлено в /tmp. І якщо в кореневій директорії
сервера такої папки немає, то при запуску сесій буде видаватися помилка.
Сервер може обробляти велику кількість сесій одночасно, і всі їхні
тимчасові файли будуть зберігатися в директорії, заданій параметром
session.save_path.
Зберігання даних на стороні клієнта здійснюється за допомогою
cookies. Роботу PHP з cookies можна настроїти, зокрема, за допомогою
параметрів session.use_cookies, session.cookie_lifetime і т.п.
Параметр session.use_cookies визначає, чи використовувати
cookies при роботі із сесіями. За замовчуванням ця опція включена (тобто
приймає значення "1").
Параметр session.cookie_lifetime задає тривалість життя
cookies у секундах. За замовчуванням це "0", тобто дані в cookies
вважаються правильними до закриття вікна браузера.
Крім цих параметрів, корисними можуть виявитися session.name,
що визначає ім'я сесії, session.auto_start, що дозволяє автоматично
запускати сесії, session.serialize_handler, що задає спосіб
кодування даних сесії, і параметр session.cache_expire, що визначає,
через скільки хвилин застаріває документ у кеші.
Ім'я сесії session.name за замовчуванням установлюється як
PHPSESSID і використовується в cookies як ім'я змінної, у якій
зберігається ідентифікатор сесії. Автоматичний запуск сесій за
замовчуванням відключений, але його можна задати, зробивши значення
session.auto_start рівним "1". Для кодування даних сесії за
замовчуванням використовується PHP. Старіння даних, збережених у кеші,
відбувається через 180 хвилин.
Існує ще безліч настроювань, з якими можна познайомитися в
документації або безпосередньо у файлі настроювань php.ini. Знайомства
з перерахованими вище параметрами досить для роботи з сесіями в PHP.
77

7.4 Робота з сесіями

Перше, що потрібно зробити для роботи з сесіями (якщо вони вже


настроєні адміністратором сервера), це запустити механізм сесій. Якщо в
настроюваннях сервера змінна session.auto_start установлена в
значення "0", то будь-який скрипт, у якому потрібно використати дані сесії,
повинен починатися з команди

session_start();

Одержавши таку команду, сервер створює нову сесію або відновлює


поточну, грунтуючись на ідентифікаторі сесії, переданому за запитом. Як це
робиться? Інтерпретатор PHP шукає змінну, у якій зберігається
ідентифікатор сесії (за замовчуванням це PHPSESSID) спочатку в cookies,
потім у змінних, переданих за допомогою POST- і GET-запитів. Якщо
ідентифікатор знайдений, то користувач вважається ідентифікованим,
здійснюється заміна всіх URL і виставляння cookies. У противному
випадку користувач вважається новим, для нього генерується новий
унікальний ідентифікатор, потім здійснюється заміна URL і виставляння
cookies.
Команду session_start() потрібно викликати у всіх скриптах, у
яких належить використовувати змінні сесії, причому до виводу яких-небудь
даних у браузер. Це пов'язане з тим, що cookies виставляються тільки до
виводу інформації на екран.
Одержати ідентифікатор поточної сесії можна за допомогою функції
session_id().
Для наочності сесії можна задати ім'я за допомогою функції
session_name([ім'я_сесії]). Робити це потрібно ще до ініціалізації
сесії. Одержати ім'я поточної сесії можна за допомогою цієї ж функції, що
викликана без параметрів: session_name();

Приклад. Створення сесії. Перейменуємо наш файл index.html, щоб


оброблялися PHP-скрипти, наприклад в index.php, створимо сесію й
подивимося, який вона одержить ідентифікатор й ім'я.

<?php
session_start();
// створюємо нову сесію або відновлюємо поточну
echo session_id();
// виводимо ідентифікатор сесії
?>
<html>
<head><title>My home page</title></head>
... // домашня сторінка
78

</html>
<?php
echo session_name();
// виводимо ім'я поточної сесії.
// У цьому випадку це PHPSESSID
?>

Якщо проробити то ж саме з файлом authorize.php, то значення


виведених змінних (id сесії і її ім'я) будуть такими ж, якщо перейти на нього
з index.php і не закривати перед цим вікно браузера.

Реєстрація змінних сесії

Однак від самих ідентифікатора й імені сесії нам користі для рішення
наших задач небагато. Ми ж хочемо передавати й зберігати протягом сесії
наші власні змінні (наприклад, логін і пароль). Для того, щоб цього
домогтися, потрібно просто зареєструвати свої змінні:

session_register(ім'я_змінної1, ім'я_змінної2, ...);

Помітимо, що реєструються не значення, а імена змінних.


Зареєструвати змінну досить один раз на будь-якій сторінці, де
використовуються сесії. Імена змінних передаються функції
session_register() без знака $. Всі зареєстровані в такий спосіб змінні
стають глобальними (тобто доступними з будь-якої сторінки) протягом даної
сесії роботи з сайтом.
Зареєструвати змінну також можна, просто записавши її значення в
асоціативний масив $_SESSION, тобто написавши

$_SESSION['ім'я_змінної'] = 'значення_змінної';

У цьому масиві зберігаються всі зареєстровані (тобто глобальні) змінні


сесії.
Доступ до таких змінних здійснюється за допомогою масиву
$_SESSION['ім'я_змінної'] (або
$HTTP_SESSION_VARS['ім'я_змінної'] для версії PHP 4.0.6 і більш
ранніх). Якщо ж у настроюваннях PHP включена опція
register_globals, то до сесійних змінних можна звертатися ще і як до
звичайних змінних, наприклад так: $ім'я_змінної.
Якщо register_globals=off (відключені), то користуватися
session_register() для реєстрації змінних, переданих методами POST
або GET, не можна, тобто це просто не працює.
79

Починаючи з версії PHP 5.3.0 не рекомендується для реєстрації змінних


сесії використовувати функцію session_register(). Замість цього, для
реєстрації змінних сесії рекомендується користуватися масивом $_SESSION.

Приклад. Реєстрація змінних (файл authorize.php). Зареєструємо логін і


пароль, що вводяться користувачем на сторінці авторизації.

<?php
session_start();
// створюємо нову сесію або відновлюємо поточну
if (!isset($_GET['go'])){
echo "<form>
Login: <input type='text' name='login'>
Password: <input type='password'
name='passwd'>
<input type='submit' name='go' value='Go'>
</form>";
}else {
$_SESSION['login']=$_GET['login'];
// реєструємо змінну login
$_SESSION['passwd']=$_GET['passwd'];
// реєструємо змінну passwd
// тепер логін і пароль - глобальні змінні для цієї
сесії
if ($_GET['login']=="pit" &&
$_GET['passwd']=="123") {
Header("Location: secret_info.php");
// перенаправляємо на сторінку secret_info.php
}else echo "Невірне введення,
спробуйте ще раз<br>";
}
print_r($_SESSION);
// виводимо всі змінні сесії
?>

Тепер, потрапивши на сторінку secret_info.php, та й на будь-яку


іншу сторінку сайту, ми зможемо працювати з введеними користувачем
логіном і паролем, які будуть зберігатися в масиві $_SESSION. Змінимо код
сторінки secret_info.php так:

<?php
session_start();
// створюємо нову сесію або відновлюємо поточну
print_r($_SESSION); // виводимо всі змінні сесії
80

?>
<html>
<head><title>Secret info</title></head>
<body>
<p>Тут я хочу ділитися секретами з другом Петром.
</p>
</body>
</html>

Тоді ми одержимо в браузері наступне:

Array ( [login] => pit [passwd] => 123 )


Тут я хочу ділитися секретами з другом Петром.

У підсумку одержимо список змінних, зареєстрованих на


authorize.php й, властиво, саму секретну сторінку.
Що це нам дає? Припустимо, хакер довідався, як називається сторінка з
секретною інформацією. Тоді він може спробувати просто ввести її адресу в
рядку браузера, минаючи сторінку авторизації. Щоб уникнути цього,
потрібно дописати всього пару рядків у код сторінки secret_info.php
(2-я версія secret_info.php):

<?php
session_start();
// створюємо нову сесію або відновлюємо поточну
print_r($_SESSION); // виводимо всі змінні сесії
if (!($_SESSION['login']=="pit" &&
$_SESSION['passwd']==123))
// перевіряємо правильність пароля-логіна
Header("Location: authorize.php");
// якщо помилка, то перенаправляємо на
// сторінку авторизації
?>
<html>
<head><title>Secret info</title></head>
... // тут розташовується
//секретна інформація :)
</html>

Видалення змінних сесії

Крім уміння реєструвати змінні сесії (тобто робити їх глобальними


протягом усього сеансу роботи), корисно також уміти видаляти такі змінні й
сесію в цілому.
81

Функція session_unregister(ім'я_змінної) видаляє


глобальну змінну з поточної сесії (тобто видаляє її зі списку зареєстрованих
змінних). Якщо реєстрація здійснювалася за допомогою $_SESSION
($HTTP_SESSION_VARS для версії PHP 4.0.6 і більш ранніх), то
використовують язикову конструкцію unset(). Вона не повертає ніякого
значення, а просто знищує зазначені змінні.
Де це може придатися? Наприклад, для знищення даних про
відвідувача (зокрема, логіна й пароля) після його виходу з секретної
сторінки. Якщо правильні логін і пароль збережуться й вікно браузера після
відвідування сайту не закрили, то будь-який інший користувач цього
комп'ютера зможе прочитати закриту інформацію.

Приклад. Знищення змінних сесії. У файл secret_info.php додамо


рядок для виходу на головну сторінку:

<?php
// ... php код
?>
<html>
<head><title>Secret info</title></head>
... // тут розташовується
// секретна інформація :)
<a href="index.php">На головну</a>
</html>

В index.php знищимо логін і пароль, введені раніше:

<?php
session_start();
unset($_SESSION['passwd']);
// знищуємо пароль
unset($_SESSION['login']);
// знищуємо логін
print_r($_SESSION);
// виводимо глобальні змінні сесії
?>
<html>
<head><title>My home page</title></head>
... // домашня сторінка
</html>

Тепер, щоб потрапити на секретну сторінку, потрібно буде знову


вводити логін і пароль.
82

Для того щоб скинути значення всіх змінних сесії, можна використати
функцію session_unset().
Знищити поточну сесію цілком можна командою
session_destroy(). Вона не скидає значення глобальних змінних сесії й
не видаляє cookies, а знищує всі дані, асоційовані з поточною сесією.

Приклад. Знищення сесії й глобальних змінних.

<?php
session_start(); // ініціалізуємо сесію
$test = "Змінна сесії";
$_SESSION['test']= $test;
// реєструємо змінну $test.

print_r($_SESSION);
// виводимо всі глобальні змінні

echo session_id();
// виводимо ідентифікатор сесії

echo "<hr>";
session_unset();
// знищуємо всі глобальні змінні сесії
print_r($_SESSION);
echo session_id();
echo "<hr>";
session_destroy(); // знищуємо сесію
print_r($_SESSION);
echo session_id();
?>

У результаті роботи цього скрипта будуть виведені три рядки: у


першому - масив з елементом test і його значенням, а також ідентифікатор
сесії, у другому - порожній масив й ідентифікатор сесії, у третьому -
порожній масив. Таким чином, видно, що після знищення сесії знищується і
її ідентифікатор, і ми більше не можемо ні реєструвати змінні, ні взагалі
робити будь-які дії з сесією.
83

ЛІТЕРАТУРА

1. Суэринг С., Конверс Т., Парк Д. PHP и MySQL. Библия программиста. –


М.: ООО “И.Д. Вильямс”, 2010. – 912 с.
2. Олищук А.В., Чаплыгин А.Н. Разработка Web-приложений на PHP 5.
Профессиональная работа. - М.: ООО “И.Д. Вильямс”, 2006. – 352 с.
3. Томсон Л., Веллинг Л. Разработка Web-приложений на РНР и MySQL.
- СПб: ООО «ДиаСофтЮП», 2003. — 672 с.

You might also like