Лістинг 6.4. vieworders.php — інтерфейс для перегляду файлу замовлень
<html><head>
<title> Auto Parts - Customer Orders by Mikle</title></head><body>
<hl> Auto Parts</hl> <h2>Customer Orders</h2>
<?
@$fp = fopen("$DOCUMENTROOT/../orders/orders.txt", "r");
if (!$fp) {
echo "<p><strong>No orders pending."
."Please try again later.</strong></p></body></html>";
exit; }
while (!feof($fp)) {
$order= fgets($fp, 100);
echo $order."<br>"; }
fclose($fp); ?>
</body> </html>
У цьому сценарії виконується раніше описана послідовність дій: відкриття файлу, прочитування з файлу, закриття файлу. Давайте детальніше розглянемо функції, використовувані в цьому сценарії.
Відкриття файлу для читання: fopen().Як і раніше, ми відкриваємо файл за допомогою функції fopen(). Цього разу файл відкривається лише для читання, тому використовується режим файлу "r":
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");
Визначення кінця файлу: feof().В даному прикладі використовується цикл while для прочитування з файлу до тих пір, поки не буде досягнутий кінець файлу. Перевірка на наявність кінця файлу здійснюється за допомогою функції feof():
while (!feof($fp))
Функція feof() приймає в єдиному параметрі покажчик файлу. Вона повертатиме значення true, якщо покажчик файлу знаходиться в кінці файлу. Ім'я функції легко запам'ятати, якщо знати, що feof означає File End Of File (Файл: кінець файлу).
В даному випадку (і взагалі при прочитуванні) прочитування з файлу виконується до тих пір, поки не буде досягнутий EOF.
Відрядкове прочитування: fgets(), fgetss() і fgetcsv().У даному прикладі для прочитування з файлу використовується функція fgets(): $order= fgets($fp, 100);
Ця функція використовується для прочитування з файлу по одному рядку за один раз. В даному випадку прочитування виконуватиметься до тих пір, поки не зустрінеться символ нового рядка (\n), EOF або з файлу не будуть прочитані 99 байт. Максимальна довжина прочитуваного рядка дорівнює вказаній довжині мінус один байт.
Цікавим варіантом функції fgets() є fgetss(), що має наступний прототип:
string fgetss (int fp, int length, string [allowable_tags] ) ;
Ця функція багато в чому подібна до функції fgets() за винятком того, що вона позбавлятиметься від будь-яких дескрипторів РНР і HTML, знайдених в рядку. Якщо у файлі необхідно залишити конкретні дескриптори, вони мають бути включені в рядок allowable_tags. Функцію fgetss() слід використовувати для забезпечення безпеки при прочитуванні файлу, записаного ким-небудь іншим або що містить дані, введені користувачем. Відсутність обмежень на наявність у файлі HTML-кода може привести до порушення ретельно спланованого форматування. Відсутність обмежень на наявність у файлі РНР-кода може надати зловмисному користувачеві майже повну свободу дій на сервері.
Функція fgetcsv() — ще одна варіація функції fgets(). Вона має наступний прототип:
array fgetcsv(int fp, int length, string [delimiter]);
Ця функція використовується для розділення рядків файлів при використанні як розділовий символ табуляції, як пропонувалося раніше, або комі, яка зазвичай застосовується в електронних таблицях і інших застосуваннях. Якщо потрібно відновити змінні замовлення окремо одна від одної, а не у вигляді рядка тексту, слід вдатися до функції fgetcsv(). Вона викликається подібно до функції fgets(), але їй необхідно передати роздільник, використовуваний для розділення полів. Наприклад
$order = fgetcsv($fp, 100, "\t");
отримує рядок з файлу і розбиває його при кожному виявленні символу табуляції (\t). Результуючі дані поміщаються в масив (в даному прикладі — в $order).
Параметр length має бути більше довжини щонайдовшого рядка прочитуваного файлу, вираженого в символах.
Прочитування всього файлу: readfile(), fpassthru(), file().Замість прочитування по одному рядку з файлу за один прохід можна прочитувати весь файл. Існують три різні способи.
Перший полягає у використанні функції readfile(). Весь раніше створений сценарій можна замінити одним рядком:
readfile("$DOCUMENT_ROOT/../orders/orders.txt");
Функція readfilc() відкриває файл, повторює його вміст в стандартному виводі (вікні браузеру), а потім закриває файл. Прототип цієї функції має вигляд
int readfile (string имя_файла, int [use_include_path]) ;
Необов'язковий другий параметр вказує, чи повинен РНР шукати файл в шляхи use_include_path, і діє так само, як у функції fopen(). Функція повертає загальну кількість байтів, лічених з файлу.
По-друге, можна використовувати функцію fpassthru(). Спочатку необхідно відкрити файл за допомогою функції fopen(). Потім покажчик файлу можна передати у функцію fpassthru(), яка завантажить вміст файлу, починаючи з позиції, заданої покажчиком, в стандартний вивід. Після закінчення цього процесу функція закриває файл.
Раніше приведений сценарій можна замінити функцією fpassthru() таким чином:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");
fpassthru($fp);
Функція fpassthru() повертає значення true, якщо прочитування було виконане Успішно, і false — інакше.
Третя можливість прочитування всього файлу — використання функції file(). Ця Функція ідентична функції readfile() за винятком того, що замість повторення файлу в стандартному виводі вона перетворить його в масив. Її виклик виглядає так:
$filearray = file($fp);
Цей рядок приведе до прочитування всього файлу в масив, названий $filearray. кожен рядок файлу зберігається в окремому елементі масиву.
Прочитування символу: fgetc().Ще одна можливість обробки файлів — прочитування з файлу по одному символу. Це виконується за допомогою функції fgetc(). Як свій єдиний параметр вона приймає покажчик файлу і повертає наступний символ файлу Цикл while в первинному сценарії можна замінити циклом, в якому використовується функція fgetc():
while (!feof($fp))
{
$char = fgetc($fp); if (!feof($fp))
echo ($char=="\n" ? "<br>": $char);
}
Використовуючи функцію fgetc(), цей код прочитує з файлу по одному символу за раз і зберігає його в змінній $char, поки не буде досягнутий кінець файлу. Потім виконується невелика додаткова обробка з метою заміщення текстових символів кінця рядка \n HTML-разделителями рядків <bг>. Це робиться лише для упорядковування форматування. Оскільки без цієї коду браузери не розпізнають нові рядки, весь файл був би виведений у вигляді єдиного рядка. (Спробуйте зробити це і поглянете, що вийде.) Для виконання цього завдання використовується тернарная операція.
Побічний ефект використання функції fgetc() замість функції fgets() полягає в тому, що вона повертатиме символ EOF, тоді як fgets() не робить цього. Після прочитування символу доводиться знову виконувати перевірку за допомогою функції feof(), оскільки символ EOF не повинен відображуватися у вікні браузеру.
У загальному випадку прочитування файлу символ за символом не знаходить особливого вживання, якщо лише з якої-небудь причини не потрібна посимвольна обробка файлу.
Прочитування рядків довільної довжини: fread().Останній спосіб прочитування з файлу, який ми розглянемо, — використання функції fread() для прочитування з файлу довільної кількості байтів. Ця функція має наступний прототип:
string fread(int fp, int length);
Функція прочитує length байтів або всі байти до кінця файлу, залежно від того, що станеться раніше.
Інші корисні файлові функції.Існує ряд інших файлових функцій, які часом можуть виявитися корисними.
Перевірка існування файлу: file_exists().Якщо необхідно перевірити файл на предмет існування без його відкриття, можна скористатися функцією file_exists(), як показано в наступному прикладі:
if (file_exists("$DOCUMENT_ROOT/../orders/orders.txt"))
echo "There are orders waiting to be processed."; else
echo "There are currently no orders.";
З'ясування розміру файлу: filesize().Розмір файлу можна перевірити за допомогою функції filesize(). Вона повертає розмір файлу, виражений в байтах:
echo filesize("$DOCUMENT_ROOT/../orders/orders.txt");
Ця функція може застосовуватися у поєднанні з функцією fread() для одночасного прочитування всього файлу (або певній його частині). Весь первинний сценарій можна замінити наступним кодом:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");
echo fread( $fp, filesize("$DOCUMENT_ROOT/../orders/orders.txt"));
fclose( $fp );
Видалення файлу unlink().Якщо файл замовлень необхідно видалити, це виконується за допомогою функції unlink(). (Немає жодної функції з ім'ям delete.) Наприклад:
unlink("$DOCUMENT_ROOT/../orders/orders.txt");
Ця функція повертає значення false, якщо файл не може бути видалений. Це відбуватиметься при недостатньому рівні прав доступу до файлу або якщо файл не існує.
Переміщення усередині файлу: rewind(), fseek і ftell().З'ясовувати позицію покажчика файлу усередині файлу і змінювати її можна за допомогою функцій rewind(), fseek() і ftell().
Функція rewind() встановлює заново покажчик файлу на початок файлу. Функція ftell() повідомляє в байтах позицію покажчика відносно початки файлу. У нижню частину первинного сценарію (перед командою fclose()) можна додати наступні рядки:
echo "Final position of the file pointer is ".(ftell($fp));
rewind($fp);
echo ""<br>After rewind, the position is ". (ftell ($fp) );
echo "<br>";
Функція fseek() може використовуватися для установки покажчика файлу в деяку крапку усередині файлу. Її прототип має вигляд
int fseek(int fp, int offset);
В результаті виклику функції fseek() покажчик файлу fp встановлюється в точку файлу, що має зсув offset байтів відносно початки файлу. Виклик функції rewind() еквівалентний виклику функції fseek() із зсувом, рівним нулю. Наприклад, функцію fseek() можна використовувати для знаходження середнього запису у файлі або для виконання бінарного пошуку. Часто, коли подібні завдання потрібно вирішувати стосовно досить складного файлу даних, має сенс використовувати базу даних.
Блокування файлів.Уявіть собі ситуацію, коли два клієнти одночасно намагаються замовити товар. (Ця ситуація виникає не настільки вже рідко, особливо коли Web-сайт починає обробляти значні інформаційні потоки.) Що станеться, якщо один клієнт викличе функцію fopen() і почне запис, а потім другий клієнт також викличе функцію fopen() і теж спробує виконати запис? Відповідь на це питання залежить від використовуваної операційної системи, але часто точно відповісти на них неможливо.
Щоб уникнути подібних проблем використовується блокування файлів. У РНР блокування реалізується за допомогою функції flock(). Ця функція повинна викликатися після відкриття файлу, але перед прочитуванням даних з файлу або їх записом у файл.
Прототип функції flock() виглядає так:
bool flock(int fp, int operation);
У функцію необхідно передати покажчик на відкритий файл і число, що представляє вигляд необхідного блокування. Функція повертає значення true, якщо блокування було успішно виконане, і false — інакше.
Можливі значення параметра operation перераховані в таблиці. 6.7.
Таблиця 6.7. Значення параметра operation функції flock()
Значення параметра operation | Опис |
\ | Блокування читання. Це означає, що файл може використовуватися спільно з іншими застосуваннями, що читають. |
Блокування запису. Це монопольний режим. Файл не доступний для спільного використання. | |
Зняття існуючого блокування. | |
+4 | Додавання 4 до поточного значення параметра operation запобігає іншим спробам блокування під час виконання поточного блокування. |
Якщо вирішено використовувати функцію flock(), її слід включити у всі сценарії, в яких використовується даний файл; інакше її вживання позбавлене сенсу.
Для використання блокування в даному прикладі програму processorder.php необхідно змінити таким чином:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "a", 1);
flock($fp, 2); // блокування файлу для запису
fwrite($fp, $outputstring);
flock($fp, 3); // зняття блокування запису
fclose($fp);//Следует додати блокування у файл vieworders.php:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");
flock($fp, 1); // блокування файлу для читання
flock($fp, 3); // зняття блокування запису
fclose($fp);
Тепер код надійніший, та все ще не ідеальний. Що станеться, якщо два сценарії спробують одночасно виконати блокування? Це привело б до конфлікту, коли процеси змагаються за установку блокування, але не відомо, якому з них це удасться, що, у свою чергу, могло б породити нові проблеми. Завдання можна вирішити значно успішніше, використовуючи СУБД.
Раціональніший спосіб обробки: системи управління базами даних.До цих пір у всіх розглянутих прикладах використовувалися двовимірні файли. Далі розглядатиметься вживання MYSQL — системи управління реляційними базами даних. Для чого це потрібно?
Проблеми, зв'язані з використанням двовимірних файлів. При роботі з двовимірними файлами виникає ряд проблем:
· Коли двовимірні файли стають великими, робота з ними істотно сповільнюється.
· Пошук конкретного запису або групи записів в двовимірному файлі утруднений. Якщо записи впорядковані, для пошуку в ключовому полі можна використовувати який-небудь з видів бінарного пошуку у поєднанні з вживанням записів фіксованої довжини. Якщо потрібно знайти інформацію, відповідну певному шаблону, доведеться прочитати і перевірити кожен із записів окремо.
· Конкуруючий доступ може породжувати проблеми. Вже було показано, як блокуються файли, але це може привести до виникнення описаною раніше конфліктної ситуації. Крім того, це може привести до утворення "вузького місця" в мережі. При досить інтенсивному інформаційному потоці великій групі користувачів може потрібно чекати розблокування файлу, перш ніж вони зможуть розмістити свої замовлення. Якщо чекання продовжиться дуже довго, люди звернуться за покупкою куди-небудь в інше місце.
· Вся до цих пір розглянута обробка файлів зводилася до послідовної обробки — тобто прочитування починалося з початку файлу і виконувалося до його кінця. При необхідності вставити записи або видалити їх з середини файлу (тобто при необхідності довільного доступу), це може виявитися скрутним — врешті-решт, доведеться рахувати весь файл в пам'ять, виконати зміни і знову записати весь файл. При роботі з великими файлами даних цей процес зв'язаний із значним перевантаженням системи.
· Окрім обмежень, що накладаються правами доступу до файлів, не існує жодного способу забезпечення різних рівнів доступу до даних.
Як ці проблеми вирішуються за допомогою СУРБД.Системи управління реляційними базами даних (СУРБД) вирішують всі ці проблеми:
СУРБД можуть забезпечити швидший доступ до даних, чим двовимірні файли. А MYSQL, система управління базами даних, володіє одними з найвищих показників продуктивності серед всіх СУРБД.
· У СУРБД можна легко відправляти запит для витягання наборів даних, соответствующих певним критеріям.
· СУРБД володіють вбудованими механізмами обробки конкуруючих звернень, що дозволяє програмістові не турбуватися про це.
· СУРБД забезпечують довільний доступ до даних.
· СУРБД володіють вбудованими системами визначення прав доступу. MYSQL володіє особливо великими можливостями в цій області.
Ймовірно, головна спонукальна причина використання СУРБД полягає в тому, що всі (або, щонайменше, більшість) функціональні можливості, потрібні від системи зберігання даних, в ній вже реалізовані. Звичайно, можна було б створити власну бібліотеку РНР-функций, але навіщо ж заново винаходити колесо?
Доступ до баз даних.
Підготовка бази.Перед організацією системи доступу до баз даних, необхідно мати ці бази. Далі розглядається створення учбової бази даних, використовуваної в прикладах.
Запустивши монітор mysql і реєструється в системі, створимо базу даних books:
mysql> create database books;
Після входу в систему спочатку потрібно буде визначити базу даних, з якою необхідно працювати. Це можна зробити, набравши:
mysql> use dbname;
де dbname — ім'я відповідної бази даних.
Можна і не набирати команду use, але тоді слід вказати базу даних при вході систему:
mysql dbname -h hostname -u username -p
В даному прикладі скористаємося базою даних books:
mysql> use books;
Для з'єднання РНР-сценариев з MYSQL потрібно буде набудувати користувача. В цьому випадку потрібно застосувати принцип найменших привілеїв: навіщо права сценаріям?
В більшості випадків сценаріям знадобиться проводити над рядками таблиць лише такі операції: SELECT, INSERT, DELETE і UPDATE. Можна поступити таким чином:
mysql> grant select, insert, delete, update
-> on books.*
-> to bookorama identified by 'bookoramal23' ;
He забувайте про безпеку! Такий пароль, звичайно, нікуди не годиться.
Наступний етап налаштування бази даних — створення таблиць. Це робиться за допомогою SQL-команды CREATE TABLE.
Лістинг 7.5 містить SQL-код для створення цих таблиць, при цьому мається на увазі, що база даних books вже створена.
SQL-код створення таблиць запускається таким чином:
> mysql -h host -u bookorama books -p < books.sql
В даному випадку дуже зручно використовувати перепризначення файлів, оскільки передбачається, що до виконання SQL-код редагується в будь-якому текстовому редакторові.
Дата добавления: 2016-04-02; просмотров: 683;