Archive for category PHP

PHP-кодеру на пам’ять. Випуск 2

Можливі проблеми з UTF-8

Якщо в проекті використовуються файли з кодировкою Юнікод, то можлива наступна проблема:
Warning: Cannot modify header information – headers already sent by (output started at…
Якщо все перевірено, ніде немає зайвих пробілів і т.д., а проблема збереглась, то це може означати, що файл був збережений не в “чистому” UTF-8, а в UTF-8 з сигнатурою(BOM). Деякі текстові редактори уміють зберігати файли в обох варіантах – наприклад Scite або Notepad2. Потрібно просто відкрити і зберегти файл в потрібній кодировці.
Через UTF-8 з сигнатурою(BOM) можлива також поява порожнього рядку “нізвідки” при виводі HTML через PHP.

foreach – деякі особливості

Щоб вивести певні результати за допомогою цього циклу можливі кілька варіантів. А от щоб ЗМІНИТИ САМ МАСИВ допустимий лише один шлях:
Працює:

foreach($rows as $k=>$v){
$rows[$k]['news_date'] = date('r', strtotime($rows[$k]['news_date']));
}

Не працює (оскільки ми змінюємо змінну зі значенням, а не сам масив):

foreach($rows as $k=>$v){
$v['news_date'] = date('r', strtotime($v['news_date']));
}

Змінні в PHP

Наштовхнувся в одному блозі на цікавий пост присвячений двом змінним в РНР:
DIRECTORY_SEPARATOR і PATH_SEPARATOR.

DIRECTORY_SEPARATOR – як випливає з назви, зберігає розділювач між папками, який різниться в залежності від ОС (’/'- Unix, ‘\’ – Windows).
Незважаючи на те, що Windows зрозуміє вас навіть, якщо розділяти папки символом ‘/’, всеодно коректніше використовувати DIRECTORY_SEPARATOR

PATH_SEPARATOR - зберігає розділювач для параметру РНР include_path (всі шляхи, по яким ваші скрипти шукають бібліотеки для підключкення)
Так ось, під Windows цей розділювач виглядає як ‘;’ під Unix – ‘:’
Коли потрібно підключити якусь бібліотеку (то й же Зенд) і працювати зі скриптом під різними ОС, виникають складнощі.
Донедавна я вирішував ці складнощі “геніальним” скриптиком:

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
ini_set('include_path', ini_get('include_path') . ';' . getcwd() . DS . '..' . DS. 'lib'  .';');//WIN
} else {
ini_set('include_path', ini_get('include_path') . ':' . getcwd() . DS . '..' . DS. 'lib'  . ':');//another OS
}

Зрозуміло, що в “цивілізованому світі” (а тепер і я) роблять по-іншому:

ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR. getcwd() . DS . '..' . DS. 'lib'  . PATH_SEPARATOR);

Правильний стиль написання коду від Zend

For files that contain only PHP code, the closing tag (”?>”) is never permitted. It is not required by PHP, and omitting it´ prevents the accidental injection of trailing white space into the response
Ось як воно… А взагалі, почитати рекомендації від Zend ніколи зайвим не буде.

Економія пам’яті в PHP

При операціях з картинками на сервері варто слідкувати за витратами пам’яті на сервері і не забувати про функцію imagedestroy. Наприклад:

$src = imagecreatefromjpeg($file_temp);
.... якийсь код
imagedestroy($src);

До речі, для тестування і моніторингу скільки саме пам’яті використовує РНР на певний момент, застосовується функція memory_get_usage() (без параметрів)

Коментарів немає

Сесії в PHP та куки

c2Тема ніби не з найскладніших, проте в свій час я виявив в ній багато “нового та невідомого”. В результаті з’явилась ця стаття, в котрій я спробував базово окреслити основні особливості функціонування та використання вищезгаданих технологій.

Специфіка протоколу HTTP така, що він не підтримую постійного з’єднання. Тобто “кожний раз – як вперше”. Щоб якось ідентифікувати користувача використовуються сесії та куки.

Спочатку про куки

Вперше звертаючись до сервера, браузер отримує відповідь, в якій будуть куки. Після цього всі свої звернення до сервера браузер буде супроводжувати “прикріпленням” отриманих кук.
По стандарту вони мають структуру:
Set-Cookie: RMID=732423sdfs73242; expires=Fri, 31-Dec-2010 23:59:59 GMT; path=/; domain=.example.net
Кука має ім’я RMID і значення «732423sdfs73242». Термін її зберігання сплине 31 грудня 2010 року в 23:59:59. Шлях «/» і домен «example.net» показують , що можна відкривати куку при перегляді будь-якої сторінки в домені example.net
Браузери дозволяють(на даний момент) зберігати від 30 до 50 кук з одного домена. Firefox 3 наразі зберігає куки в файлі формату SQLite (на них можна подивитись через, скажімо, Firecookie ), ІЕ 7 куки зберігає в звичайних текстових файлах.

Можливі ризики пов’язані з cookies:
1) Завдяки “стороннім” кукам, які можуть розміщуватись рекламними банерами, компанії-господарі цих банерів можуть відслідковувати куди переміщався користувач на сайтах де ці банери встановлені(вихід – можна заборонити браузеру приймати сторонні куки).
Куки може зчитати лише той сайт, якому це ДОЗВОЛЕНО в параметрах конкретно взятого кука (якщо, звичайно, в самому браузері немає “дірок”)
2)Перехоплення трафіка призведе до того, що інформація, яка міститься в куках потрапить до сторонніх людей (вихід – застосовувати https)
3)Міжсайтовий скриптинг – куки передаються на домени, на які передаватись не мали б за допомогою JavaScript і т.д.(вихід – тут уже все залежить від надійності браузера та інших факторів, наприклад – чи ввімкнута в настройках РНР опція session.cookie_httponly)

Використання в РНР:
bool setcookie ( string $name [, string $value [, int $expire [, string $path [, string $domain [, bool $secure [, bool $httponly ]]]]]] )

  • string $name – ім’я куки
  • string $value – її значення
  • int $expire – термін використання, якщо немає – то до кінця сессії
  • string $path – сторінка з яких кука буде доступна, якщо немає – то для всіх, що знаходяться в тому ж каталозі, в якому скрипт, що ВСТАНОВЛЮЄ цю куку.
  • string $domain – домен куку, якщо немає – то встановлюється поточний
  • bool $secure – якщо стоїть 1, то куки будуть передаватись на сервер тільки при HTTPS з’єднанні (але користувачу ці куки ВСТАНОВЛЮЮТЬСЯ і при звичайному з’єднанні). Наприклад: setcookie(”name”, $value, time() + 600,”",”",1);
  • bool $httponly -(з’явився лише в РНР 5.2, якщо стоїть 1, то куки стануть доступні лише через HTTP протокол (і не доступні для JS та інших скриптів). А взагалі, цей параметр можна виставити і в настройках PHP.
  • Приклад:

    setcookie(”name”, $value, time() + 600,”/web/index.php”, “.server.com”); //куки на 10 хвилин, доступні тільки з сторінки /web/index.php, яка знаходиться на одному з доменів server.com

    $_COOKIE['user_login'] – прочитати куку

    setcookie(”name”) – видалити куку

    Сесії

    Сесії – це технологія, коли дані про користувача зберігаються на сервері. Де саме? Це залежить від параметрів (в РНР – це session.save_path)
    Найчастіше – це звичайні текстові файли(сесії можуть зберігати ще й в БД) з іменем sess_281a977c051ca8c5e24b30f2a492eec2.txt Тут 281a977c051ca8c5e24b30f2a492eec2 – це ідентифікатор сесії.

    Але головна проблема – як зв’язати браузер і сервер? Зараз існують 2 шляхи:

    1) Через куки – так робиться найчастіше. Але якщо куки відключенні і параметри дозволяють, то використовується спосіб 2:
    2)Через сторінку, яка повертається браузеру, сервер сам прописує ідентифікатор сесії в лінки сторінки, в результаті отримуються ссилки виду
    site.com.ua/files/Grupa.html?PHPSESSID=6b07180cc1935abde10e4cf0527db4b1
    Цей спосіб є не таким безпечним і значно менш популярним.
    Вибір між цими двома способами в PHP здійснюється через маніпуляцію параметрами session.use_cookies,session.use_only_cookies, session.use_trans_sid

    Час життя сесії як правило 24 хвилини(цей параметр по замовчуванню, його, звичайно, можна змінювати) з моменту останньої активності користувача.

    Використання:

    session_start();
    $_SESSION['username'] = “username”;

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

    P.S. В процесі розбору з цими технологіями сильно допомогли два плагіни для Firefox: Firecookie(по суті – це плагін для Firebug) і Live HTTP headers

    Коментарів немає

    Підрахунок користувачів на сайті через сесію

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

    
    <?php
     session_start();
    function getUsersOnline() {
     $count = 0;
    $handle = opendir(session_save_path());
     if ($handle == false) return -1;
    while (($file = readdir($handle)) != false) {
     if (ereg("^sess", $file)) $count++;
     }
     closedir($handle);
    
    return $count;
     }
     ?>
    

    Коментарів немає

    PHP-кодеру на пам’ять

    Дебагінг без зайвих труднощів

    Для дебагінгу РНР-програмісти в незалежності від власної кваліфікації часто використовують конструкції echo, var_dump(), print_r і навіть комбінацію echo ‘<pre>’;print_r($obj);echo ‘</pre>’;
    Ясно, що в цьому випадку вся потрібна інформація виводиться прямо в браузер. У випадку, якщо потрібні дані будуть містити HTML-теги, браузер їх одразу інтерпретує, і програміст майже нічого не побачить. Наприклад, наступний код не виведе в браузері абсолютно нічого:

    <?
    $tablelist='<input name=csv_dbtable type=hidden value=123>';
    echo $tablelist; //Виведе <input name=csv_dbtable type=hidden value=123> і браузер це не покаже
    ?>

    В такому випадку доцільно застосовувати спеціальну РНР функцію – htmlentities. Вона замінює всі теги на спеціальні символи і забезпечує потрібний вигляд інформації, що виводиться

    <?
    $tablelist='<input name=csv_dbtable type=hidden value=123>';
    echo  htmlentities($tablelist); //Виведе <input name='csv_dbtable' type=hidden value=> через спецсимволи, а браузер це нормально покаже
    ?>

    Генерація картинок в РНР

    В PHP можлива робота з графічними файлами через використання бібліотек GD або ImageMagick. Одним із цікавих прикладів такої “співпраці” може бути … генерація картинки з самого php-файлу. Достатньо відправити правильний заголовок браузеру. Наприклад такий (генеруємо png-файл з файлу png_resize.php):

    <?
    header("Content-type: image/png");
    //далі йде код по створенню файла
    ?>

    Потім залишається викликати цей файл:

    <img id=text_player_box src=some_folder/png_resize.php?parametrs=some_parametrs>

    Редирект сторінок в РНР

    При використанні редиректів варто не забувати примусово завершувати виконання скрипта.

    <?
    header("Location: www.google.com");
    exit;
    ?>

    Інакше потім довго доведеться шукати джерело помилки. По ідеї, це очевидно, але все-таки озвучу ще раз: header лише формує заголовки, які будуть відіслані браузеру, автоматичне завершення виконання скрипта НЕ ВХОДИТЬ в її обов’язки.

    Витягнути дробову частину числа на РНР

    Можна так:

    $t=$t-floor($t);

    або так:

    $t=substr($t,2,2);

    Дехто навіть умудряється використовувати explode()

    Повідомлення про помилки в коді

    Зрозуміло, що на “бойовому” сервері помилки на очі користувачам виводити не варто. На томість під час розробки без цього – ніяк.
    Зручно в конфігураційному файлі створити константу, якій присвоювати значення (показувати чи не показувати помилки) в залежності від того, де виконується код:

    <?php
    if($_SERVER['REMOTE_ADDR']!='127.0.0.1'){
    	//інші налаштування....
    	define('SHOW_ALL_ERRORS', 0);
    } else {
    	//інші налаштування....
    	define('SHOW_ALL_ERRORS', 1);
    
    }
    ?>
    

    А потім в коді орієнтуватись на цю константу:

    if (SHOW_ALL_ERRORS == 2) {
    			error_reporting(E_ALL|E_STRICT);//Report all errors plus E_STRICT errors
    			ini_set('display_errors', 1);
    		}
    		if (SHOW_ALL_ERRORS == 1) {
    			error_reporting(E_ALL ^ E_NOTICE);//Report all errors except E_NOTICE; Also could be E_ALL &amp;amp; ~E_NOTICE
    			ini_set('display_errors', 1);
    		}
    		if (SHOW_ALL_ERRORS == 0) {
    			ini_set('display_errors', 0);
    		}
    

    1 Коментар