1. Протокол HTTP. Введення

Відразу хочу уточнити одну маленьку річ. Страшне слово протокол є не що
інше, як угода безлічі людей, просто в один прекрасний момент люди
вирішили: "Давайте будемо робити так, і тоді все буде в порядку". Боятися нема чого,
все просто до неподобства і це неподобство ми зараз будемо розкривати. Отже, що
ж це таке протокол HTTP і з чим його їдять?


1.1 Клієнт і сервер


Чудес в світі, а тим більше в світі программізма і інтернету не буває! Засвойте
це як непорушну істину. І, якщо програма не працює або працює не так як
хочеться, то, значить, швидше за все, вона або написана не правильно, або містить
помилки. Отже, як же все-таки браузер просить сервер надіслати йому хоч
що-небудь? Та дуже просто! Треба тільки трохи розслабитися і почати отримувати
задоволення від процесу 🙂


1.2. Пишемо наш перший HTTP запит


Якщо Ви думаєте, що все дуже складно, то Ви помиляєтеся. Людина так
влаштований, що просто не здатний створювати щось складне, інакше він сам у цьому
заплутається 🙂 Отже, є браузер і є Web-сервер. Ініціатором обміну даними
завжди виступає браузер. Web-сервер нікому, ніколи просто так нічого не
пошле, щоб він що-небудь відправив браузеру – треба, щоб браузер про це
попросив. Найпростіший HTTP запит миє виглядати, наприклад, так:

GET http://www.php.net/ HTTP/1.0



Ви можете виконати цей запит дуже просто. Запустіть програму
telnet.exe, введіть в якості хоста www.php.net, вкажіть порт 80, і просто
наберіть даний запит, натиснувши два рази Enter в якості

. У відповідь ви
отримаєте HTML код головної сторінки сайту www.php.net.


1.3 Структура запиту


Розглянемо, з чого складається HTTP запит. Все досить просто. Почнемо з
того, що HTTP запит – це цілком осмислений текст. З чого ж він полягає в
загальному випадку? Будемо розглядати протокол HTTP 1.0. Отже:

Request-Line [ General-Header | Request-Header |
Entity-Header ]
[ Entity-Body ]



Нам вкрай цікаві методи обробки GET і POST. Методом GET можна просто
передати параметри в скрипт, а методом POST можна емулювати submit форми.

Для методу GET, Request-URI може виглядати, наприклад, так:
“/index.html?param1=1&param2=2”.


А тепер після таких страшних слів давайте спробуємо трохи заспокоїтися і
зрозуміти, що ж нам треба? Розуміти ми природно будемо на прикладах.

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


2 Метод GET


Напишемо наш запит.

GET http://www.site.ru/news.html
HTTP/1.0

Host: www.site.ru

Referer:
http://www.site.ru/index.html

Cookie: income=1


Даний запит говорить нам про те, що ми хочемо отримати вміст сторінки за
адресою http://www.site.ru/news.html, використовую метод GET. Поле Host говорить про
тому, що дана сторінка знаходиться на сервері www.site.ru, поле Referer говорить
про те, що за новинами ми прийшли з головної сторінки сайту, а поле Cookie
говорить про те, що нам була присвоєна така-то кука. Чому так важливі поля Host,
Referer та Сookie? Тому що нормальні програмісти при створенні динамічних
сайтів перевіряють дані поля, які з'являються в скриптах (РНР в тому числі) в
вигляді змінних. Для чого це треба? Для того, наприклад, щоб сайт не грабували,
тобто НЕ нацьковували на нього програму для автоматичного скачування, або для
того, щоб зайшов на сайт людина завжди попадав би на нього тільки з головною
сторінки і.т.д.

Тепер давайте уявимо, що нам треба заповнити поля форми на сторінці та
відправити запит з форми, нехай в цій формі буде два поля: login і password
(Логін і пароль), – і, ми природно знаємо логін і пароль.

GET
http://www.site.ru/news.html?login=Petya% 20Vasechkin & password = qq
HTTP/1.0

Host: www.site.ru

Referer:
http://www.site.ru/index.html

Cookie: income=1


Логін у нас "Petya Vasechkin" Чому ж ми повинні писати Petya% 20Vasechkin?
Це з = за того, що спеціальні символи можуть бути розпізнані сервером, як
ознаки наявності нового параметра або кінця запиту і.т.д. Тому існує
алгоритм кодування імен параметрів та їх значень, щоб уникнути оштбочних
ситуацій у запиті. Повний опис цього алгоритму можна знайти тут, а в
PHP є функції rawurlencode і rawurldecode для кодування і декодування
відповідно. Хочу отметеіть, що декодування РНР робить сам, якщо в запиті
були передані закодовані параметри. На цьому я закону першу главу знайомства
c протоколом HTTP. У следуючей главі ми розглянемо побудову запитів типу POST
(У перекладі з англійської – "відправити"), що буде набагато цікавіше, тому що
саме даний тип запитів використовується при відправленні даних з HTML форм.


3. Метод POST.


У разі HTTP запиту типу POST існує два варіанти передачі полів з
HTML форм, а саме, використовуючи алгоритм application / x-www-form-urlencoded і
multipart / form-data. Відмінності між даними алгоритмами досить істотні.
Справа в тому, що алгоритм першого типу створювався давним-давно, коли в мові
HTML ще не передбачали можливість передачі файлів через HTML форми. Отже,
давайте розглянемо ці алгоритми на прикладах.


3.1 Content-Type: application/x-www-form-urlencoded.


Пишемо запит, аналогічний нашому запиту GET для передачі логіна і пароля,
який був розглянутий в попередньому розділі:

POST http://www.site.ru/news.html HTTP/1.0

Host: www.site.ru

Referer: http://www.site.ru/index.html

Cookie: income=1

Content-Type:
application/x-www-form-urlencoded

Content-Length:
35

login=Petya%20Vasechkin&password=qq


Тут ми бачимо приклад використання Content-Type і Content-Length полів
заголовка. Content-Length говорить, скільки байт буде займати область даних,
яка відділяється від заголовка ще одним перекладом рядка
. А ось
параметри, які раніше для запиту GET поміщалися в Request-URI, тепер
знаходяться в Entity-Body. Видно, що вони формуються точно також, просто треба
написати їх після заголовка. Хочу відзначити ще один важливий момент, ніщо не
заважає, одночасно з набором параметрів у Entity-Body, поміщати параметри з
іншими іменами в Request-URI, наприклад:

POST http://www.site.ru/news.html?type=user
HTTP/1.0

…..

login=Petya%20Vasechkin&password=qq


3.2 Content-Type: multipart/form-data


Як тільки інтернет світ зрозумів, що непогано б було через форми відсилати ще й
файли, так W3C консорціум взявся за доопрацювання формату POST запиту. До того
час уже досить широко застосовувався формат MIME (Multipurpose Internet Mail
Extensions – багатоцільові розширення протоколу для формування Mail повідомлень),
тому, щоб не винаходити велосипед заново, вирішили використати частину даного
формату формування повідомлень для створення POST запитів в протоколі HTTP.

Які ж основні відмінності цього формату від типу
application/x-www-form-urlencoded?

Головна відмінність у тому, що Entity-Body тепер можна поділити на розділи,
які поділяються межами (boundary). Що найцікавіше – кожен розділ
може мати свій власний заголовок для опису даних, які в ньому
зберігаються, тобто в одному запиті можна передавати дані різних типів (як в
Mail листі Ви одночасно з текстом можете передавати файли).

Отже, приступимо. Розглянемо знову все той же приклад з передачею логіну та
пароля, але тепер у новому форматі.

POST http://www.site.ru/news.html HTTP/1.0

Host: www.site.ru

Referer: http://www.site.ru/index.html

Cookie: income=1

Content-Type: multipart/form-data;
boundary=1BEF0A57BE110FD467A

Content-Length:
209

–1BEF0A57BE110FD467A

Content-Disposition:
form-data; name=”login”



Petya
Vasechkin

–1BEF0A57BE110FD467A

Content-Disposition:
form-data;
name=”password”



qq

–1BEF0A57BE110FD467A–


Тепер давайте розбиратися в тому що написано. 🙂 Я спеціально виділив
деякі символи
жирним, щоб вони не зливалися з даними. Придивившись
уважно можна помітити поле boundary після Content-Type. Це поле задає
роздільник розділів – кордон. В якості кордону може бути використана
рядок, що складається з латинських букв і цифр, а так само з ще деяких символів
(На жаль, не пам'ятаю яких ще). У тілі запиту в початок кордону додається
"–", А закінчується запит – кордоном, до якої символи "-" додаються ще
і в кінець. У нашому запиті два розділи, перший описує поле login, а другий
полі password. Content-Disposition (тип даних у розділі) говорить, що це будуть
дані з форми, а в полі name задається ім'я поля. На цьому заголовок розділу
закінчується і далі слідує область даних розділу, в якому міститься
значення поля (кодувати значення не потрібно!).

Хочу звернути Вашу увагу та те, що в заголовках розділів не треба
використовувати Content-Length, а ось в заголовку запиту треба і його значення
є розміром всього Entity-Body, що стоїть після другого
, Наступного за
Content-Length: 209
. Тобто Entity-Body відділяється від заголовка додатковим
переведенням рядка (що можна помітити і в розділах).

А тепер давайте напишемо запит для передачі файлу.

POST http://www.site.ru/postnews.html
HTTP/1.0

Host: www.site.ru

Referer:
http://www.site.ru/news.html

Cookie: income=1

Content-Type:
multipart/form-data; boundary=1BEF0A57BE110FD467A

Content-Length:
491

–1BEF0A57BE110FD467A

Content-Disposition:
form-data; name=”news_header”



Приклад
новини

–1BEF0A57BE110FD467A

Content-Disposition:
form-data; name=”news_file”; filename=”news.txt”

Content-Type:
application/octet-stream

Content-Transfer-Encoding:
binary



А ось така новина, яка лежить у файлі
news.txt

–1BEF0A57BE110FD467A–


У даному прикладі в першому розділі пересилається заголовок новини, а в другому
розділі пересилається файл news.txt. Уважний та побачить поля filename і
Content-Type у другому розділі. Поле filename задає ім'я пересилається файлу, а
полі Content-Type – тип даного файлу. Application / octet-stream говорить про те,
що це стандартний потік даних, а Content-Transfer-Encoding: binary говорить на
про те, що це бінарні дані, нічим не закодовані.

Дуже важливий момент. Більшість CGI скриптів написано розумними людьми, тому
вони люблять перевіряти тип прийшов файлу, який стоїть в Content-Type. Навіщо?
Найчастіше закачування файлів на сайтах використовується для отримання картинок від
відвідувача. Так ось, браузер сам намагається визначити що за файл відвідувач
хоче відправити і вставляє відповідний Content-Type до запиту. Скрипт його
перевіряє при отриманні, і, наприклад, якщо це не gif або не jpeg ігнорує
даний файл. Тому при "ручному" формуванні запиту подбайте про значення
Content-Type, щоб воно було найбільш близьким до формату файла, що передається.
















image/gif для gif
image/jpeg для jpeg
image/png для png
image/tiff для tiff (що використовується вкрай рідко, аж надто ємний
формат)

У нашому прикладі формується запит, в якому передається текстовий файл.
Точно так само формується запит для передачі бінарного файлу.


4. Постскриптум.


Думаю, що про передачу запитів на сервер не варто розповідати докладно. Це
вже справа суто РНР техніки :-). Досить уважно прочитати розділ про
функціях роботи з сокетами, або про функції модуля CURL в офіційній
документації РНР.

З вище сказаного, сподіваюся тепер зрозуміло, чому питання: "Як мені
сформувати POST запит, використовуючи функцію header? "- безглуздий. Функція
header (string) додає запис тільки в заголовок запиту, але ніяк не в тіло
запиту.

Є ще один тип запитів – Content-Type: multipart / mixed, сподіваюся після
прочитання цієї статті Ви легко розберетеся з даним типом самі. Докладно
вивчити його можна Тут

Про запитах інших типів можна прочитати в офіційній специфікації протоколу
HTTP 1.0 тут.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*