Доброго дня. В даній статті ми розглянемо сесії PHP, механізм через який відбувається збереження даних сесії, і використання даного механізму у мові С++. Розглянемо наступний PHP-код:
<?php
  // page1.php

  session_start() ;

  echo '<meta charset="UTF-8">' ;
  echo '<h1>Вітаю на сторінці сесій</h1>' ;

  echo '<h2>Шлях для збереження даних сесій: '.session_save_path().'</h2>' ;

  $ustr = $_SESSION ['MySiteUserName'] ;

  if (strlen($ustr)==0)
  {
    echo 'Користувача поточної сесії не встановлено, встановлюю.' ;
    
    $_SESSION ['MySiteUserName'] = 'UserName1' ;
    $_SESSION ['cookie1'] = 'MyCookieValue1' ;
    $_SESSION ['cookie2'] = 12345 ;
  }
  else
  {
    echo 'Користувач поточної сесії: ' . $ustr ;
  }

?>
На самому початку скрипта використовується функція session_start(), яка ініціалізовує підсистему сесій PHP. Тобто вона перевіряє, чи не встановлена для поточного користувача сесія через файли куки або дані HTTP-запиту, і якщо так — визначає встановлені змінні для даної сесії за її ідентифікатором. На комп'ютер користувача передається тільки ID сесії, на подобі значення “aqm0g0gfpoao0ro4icvh4k2360”. Далі відбувається вивід деякої інформації: HTML-теґ meta, який забезпечує нормальне відображення українських символів, привітання сторінки і інформація про директорію, у якій зберігаються файли усіх PHP-сесій. Після виводу інформації, ми визначаємо значення змінної сесії “MySiteUserName”, будемо вважати, що у ній мітиться ім'я облікового запису користувача. Усі інші мета-змінні PHP-сесії, які попередньо були встановлені скриптами, можна так само отримати з змінної-масиву _SESSION, вказуючи в якості індексу назву необхідної мета-змінної. Для простоти, відкинутий механізм авторизації користувача. Якщо дана змінна пуста (її довжина рівна 0), встановлюємо необхідні значення мета-змінних поточної сесії — саму змінну в якій міститься тестове ім'я користувача і деякі дані (змінні cookie1 i cookie2). Якщо ж значення змінної сесії MySiteUserName не пусте, виводимо її на екран. Після виконання даного скрипта на Веб-сервері можна отримати наступний результат: php_sesion_start_init_ Після обновлення сторінки, ми побачимо, що у нас з'явилось ім'я користувача (спрацювала підсистема PHP-сесій): inited_php_session_with_user_name_browser_output

Механізм створення сесій

Сесії створюються за допомогою даних куки (Cookie), які встановлюються за допомогою HTTP-заголовка Set-Cookie (про методи POST і GET ми говорити в даному разі не будемо). Після встановлення даних куки, вони передаються між сервером і клієнтом в двосторонньому напрямку. Так сайт визначає що ви це ви, перечитуючи значення іншого HTTP-заголовку — Cookie. Даний HTTP-заголовок містить усі попередньо встановлені сервером дані. В нашому випадку, підсистема сесій PHP встановлює тільки одну куки-змінну - PHPSESSID, яка передається від серверу до клієнта (де зберігається, найчастіше, у браузері) і від клієнта до сервера (де серверна програма на подобі Apache або Nginx зчитує її і встановлює у мета змінну HTTP_COOKIE, детально про усі мета-змінні і ви можете прочитати у статтях “Короткий опис CGI” і “CGI-програми на С++”). Усі інші дані мета-змінних сесії, зберігаються на сервері. У моєму випадку, усі дані зберігаються у каталозі “/var/lib/php5”, а дані окремих сесій зберігаються у файлі, який у своїй назві містить ідентифікатор сесії: PHP_session_saved_file За допомогою даних файлів (у нашому випадку це “sess_aqm0g0gfpoao0ro4icvh4k2360”), PHP кожного разу відновлює дані сесії, коли користувач з відповідною куки-змінною, встановленою у заголовках HTTP-запиту, підключається до сервера, щоб отримати документ за певною адресою.

Встановлюємо куки за допомогою С++

Даний механізм сесії, звичайно, можна реалізувати у C/C++. Тим більше, що сам PHP реалізований на мові програмування С. Але в загальному, написати серверну програму, яка видає документи і створює сесії можна на любій мові, яка підтримує вивід тексту і даних у стандартний потік виводу, будь це С++, Python, Perl, Java чи хоч Асемблер. Але як це зробити? Як встановити змінні куки на клієнті користувача? Виконати дану операцію дуже просто: необхідно перед виводом заголовку типу контенту (“Content-type”) і усіх даних вивести у стандартний потік виводу заголовок “Set-Cookie:”, після якого повинні розміщуватись усі необхідні дані куки, які ви бажаєте встановити на клієнті. В якості каркасу програми, візьмемо C++ CGI-програму з статті “CGI-програми на С++”. Там також розміщені інструкції, як налаштувати системe для запуску CGI-програм на сервері. Також зробимо модифікацію: перед усіма даними HTML-документу і заголовком “Content-Type”, виведемо додатковий HTTP-заголовок для встановлення куки-змінних:
#include <iostream> 
using namespace std; 
 
int main (int argc, char** argv) 
{
  // Встановлюємо куки-змінні поточного клієнта серверу
  cout << "Set-Cookie: MyCPPCookie=this_is_from_kytok_org_ua\n" ;
  cout << "Set-Cookie: data=12345\n" ;
  
  // Даний HTTP-заголовок вказує, що усі наступні
  // дані це HTML-код
  cout << "Content-Type: text/html; charset=UTF-8\n\n" ; 

  // HTML-документ
  //cout << "<meta charset=\"UTF-8\">" ;
  cout << "<h1>Привіт, Світ! Це С++ програма, яка встановлює куки.</h1>" ; 

  return 0; 
}
Після компіляції даного коду, встановлення у виділену директорію на сервері, можна отримати наступний результат: cookie_in_browser_addedby_cpp Як бачимо, клієнт (в даному випадку браузер Firefox) містить куки в якості мета-змінних "MyCPPCookie" і "data", які ми попередньо встановили. Серверній C++ програмі потрібно прочитати мета змінну HTTP_COOKIE, для вияснення поточних змінних куки, щоб взнати, наприклад, авторизацію користувача, або інші необхідні параметри. Ми також можемо імітувати поведінку підсистеми PHP-сесій, надсилаючи клієнту куки-змінну PHPSESSID з значенням унікального ідентифікатора сесії розміром у 27 символів, який потрібно попередньо згенерувати. В даному випадку можна отримати виграш у швидкодії, використовуючи базу даних, для визначення усіх параметрів поточної сесії. Оскільки база даних (на подобі MySQL або PostgreSQL) набагато швидша ніж звичайні файли і дані у ній можна розбити по стовпцям, що не потребуватиме їхній парсинг (файл даних PHP-сесії, як показано вище, містить дані про кожну змінну - її ім'я, тип і значення). З іншої сторони, ви також можете не використовувати змінну _SESSION для збереження даних сесії (які потім відображаються у спеціальному файлі, як показано вище), а отримувати ідентифікатор PHP-сесії, і використовувати його для відновлення значень сесії з бази даних. На жаль, при всій перевазі С++ у швидкодії перед PHP, нам необхідно самостійно реалізувати практичну усю підсистему сесій, подібну до підсистеми PHP. Тобто, необхідно реалізувати усі методи встановлення необхідних змінних Cookie з відповідними значеннями; методи зчитування значень заголовків HTTP-запиту у вигляді мета-змінної HTTP_COOKIE (і усіх інших); відновлення даних сесії з бази даних або файлу; їхнє збереження у спеціальному глобальному об'єкті. З даної точки зору PHP вирішує одну з поставлених їй задач — зменшення строків створення програми.