Существует ряд других файловых функций, которые время от времени могут оказаться полезными.
Если необходимо проверить, существует ли тот или иной файл, не открывая его, можно воспользоваться функцией file_exists (), как показано в примере:
if (file_exists ("$DOCUMENT_ROOT/phpstroy/test/orders.txt"))
echo 'Имеются заказы, ожидающие обработки.';
else
echo 'В настоящий момент заказов нет';
Размер файла можно определить с помощью функции filesize ():
echo filesize ("$DOCUMENT_ROOT/phpstroy/test/orders.txt"));
Она возвращает размер файла, выраженный в байтах. Эта функция может применяться в сочетании с функцией fread () для считывания всего файла (или некоторой его части). Весь разработанный нами выше сценарий можно заменить следующим кодом:
$fp = fopen ("$DOCUMENT_ROOT/phpstroy/test/orders.txt", 'rb');
if (!$fp)
{
echo '<p><strong>Нет ожидающих заказов. '
.'Пожалуйста, попытайтесь позже. </strong></p>';
exit;
}
echo nl2br (fread ($fp, filesize ("$DOCUMENT_ROOT/phpstroy/test/orders.txt")));
fclose ($fp);
Функция nl2br () преобразовывает символы \n в выводе на HTML-дескрипторы <br>.
В окне веб-браузера это будет выглядеть ТАК.
Если после обработки заказов файл заказов должен быть удален, это можно сделать с помощью функции unlink ().
unlink ("$DOCUMENT_ROOT/phpstroy/test/orders.txt");
Эта функция возвращает значение false, если файл не может быть удален. Как правило, это происходит при недостаточном уровне прав доступа к файлу или если файл вообще не существует.
Проверять и манипулировать позицией внутри указателя можно с помощью функций rewind (), fseek (), ftell ().
Функция rewind () переустанавливает указатель файла на начало файла. Функция ftell () сообщает в байтах позицию указателя относительно начала файла. Например, в нижнюю часть первоначального сценария (перед командой fclose ()) можно поместить следующие строки:
echo 'Конечная позиция в указателе файла: '.ftell($fp);
echo '<br>';
rewind($fp);
echo 'После функции rewind () позиция составляет: '.ftell($fp);
echo '<br>';
В окне веб-браузера это будет выглядеть ТАК.
Функция fseek () может использоваться для установки указателя файла в некоторую конкретную точку внутри файла. Ее прототип имеет вид:
int fseek (resource fp, int offset) [, int whence];
В результате вызова функции fseek () указатель файла fp устанавливается в точку файла, имеющую смещение offset байт относительно позиции, заданной параметром whence (откуда). Необязательный парметр whence по умолчанию принимает значение SEET_SET, которое фактически означает начало файла. Другими возможными значениями являются SEEK_CUR (текущее положение указателя файла) и SEEK_END (конец файла).
Вызов функции rewind () эквивалентен вызову функции fseek () со смещением, равным нулю. Например, вы можете использовать функцию fseek () с целью нахождения средней записи в файле или для реализации бинарного поиска. Часто, когда подобные задачи требуется решать применительно к достаточно сложному файлу данных, имеет смысл отдать предпочтение базам данных.
Представьте ситуацию, когда два клиента одновременно пытаются заказать товар. Такая ситуация возникает не так уж редко, особенно когда веб-сайт начинает обрабатывать трафик существенного объема. Что произойдет, если один клиент вызовет функцию fopen () и начинае писать, а затем второй клиент также вызовет функцию fopen () и тоже предпримет попытку записи. Каким в результате окажется содержимое файла? Будет ли вначале записан первый заказ, а затем второй, или наоборот? Будет ли записан первый заказ или второй? Либо содержимое будет представлять собой нечто практически безполезное наподобие двух причудливым образом переплетенных заказов?. Ответы на эти вопросы зависят от конкретной используемой операционной ситемы, но чаще всего точно ответить на них невозможно.
Во избежание подобных проблем используется механизм блокирования файлов. В РНР блокирование реализуется с помощью функции flock (). Эта функция должна вызываться после открытия файла, но перед считыванием данных из этого файла или их записью в этот файл.
Прототип функции flock ()выглядит так:
bool flock (resource fp , int operation [, int &wouldblock]);
В функцию необходимо передать указатель на открытый файл и константу, представляющую вид требуемой блокировки. Функция возвращает значение true, если блокировка была успешно выполнена, и false — в противном случае. Необязательный третий параметр должен содержать true, если запрашиваемая блокировка может привести к блокированию текущего процесса (то есть, к его ожиданию).
Возможные значения параметра operation (операция) перечислены в таблице.
Значения параметра operation функции flock ()
Значение параметра operation | Описание |
LOCK_SH (в ранниз версиях — 1) |
Блокировка чтения. Файл может использоваться совместно с другими читающими приложениями |
LOCK_EX (в ранних версиях — 2) |
Блокировка записи. Это монопольный режим. Файл не доступен для совместного использования. |
LOCK_UN (в ранних версиях — 3) |
Отмена существующей блокировки. |
LOCK_UN (в ранних версиях —4) |
Предотвращающиеся другие попытки блокирования во время выполнения текущего блокирования. |
Если вы намереваетесь воспользоваться функцией flock (), ее следует включить во все сценарии, в которых задействуется данный файл; в противном случае ее применение лишено смысла.
Обратите внимание на то, что функция flock () не работает с системой NFS (сетевая файловая система) и другими сетевыми файловыми системами. Она также не работает с устаревшими файловыми системами, которые не роддерживают такую блокировку, к примеру FAT (таблица размещения файлов). В среде некоторых операционных систем она реализована на уровне процессов и не будет работать корректно, если вы используете API-интерфейс многопоточного сервера.
Для использования блокировки в рассматриваемом примере сценарий processorder.php необходимо изменить:
$fp = fopen ("$DOCUMENT_ROOT/phpstroy/test/orders.txt", 'ab');
flock ($fp, LOCK_EX); //блокировка файла для записи
fwrite ($fp, $outputstring);
flock ($fp, LOCK_UN); //снятие блокировки
fclose($fp);
Также потребуется добавить блокировки в сценарий vieworders.php:
$fp = fopen ("$DOCUMENT_ROOT/phpstroy/test/orders.txt", 'rb');
flock ($fp, LOCK_SH);//блокировка файла для чения
echo nl2br (fread ($fp, filesize ("$DOCUMENT_ROOT/phpstroy/test/orders.txt")));
flock ($fp, LOCK_UN); //снятие блокировки на чтение
fclose ($fp)
Теперь код стал более надежным, тем не менее, он все еще не идеален. Что произойдет, если два сценария попытаются одновременно запросить блокировку? Это привело бы к состоянию состязаний, когда процессоры соперничают за установку блокировки, в условиях которого неизвестно, кому из них это удастся, что в свою очередь, могло бы породить новые проблемы. Значительно больший эффект можно достичь при использовании одной из систем управления базами данных.