Еще одной распространенной задачей является работа с индексными файлами. Пусть имеется файл index.txt следующего формата:
1 Программирование
2 Программирование на РНР
3 Программирование на JavaScript
4 Программирование на ASP.NET
Каждому номеру, который обычно называют индексом, соответствует строка, называемая значением. Одной из насущных задач является определение наличия в файле заданного индекса и вывод соответствующего ему значения, если такой индекс существует. Данную задачу решает скрипт приведенный ниже.
<?php
//ищем строку с индексом 2
$index=2;
//имя файла
$filename="index.txt";
//открываем файл для чтения
$fd=fopen($filename, "r");
//читаем содержимое файла
$bufer=fread($fd, filesize($filename));
//закрываем файл
fclose($fd);
//находим строку с индексом $index
preg_match("|$index([^\n]*)|", $bufer, $matches);
//выводим результат
if(isset($matches[1])) echo $matches[1];
else echo "Позиция не найдена";
?>
В окне веб-браузера это будет выглядеть примерно ТАК.
Для вставки уникального индекса в файл необходимо определить максимальный индекс и увеличить его на единицу. Эта задача решается ниже приведенном скрипте:
<?php
//имя файла
$filename="index.txt";
//помещаем содержимое файла в массив $lines
$lines=file($filename);
//в цикле формируем массив индексов
foreach($lines as $line)
{
//обнуляем массив
unset($matches);
//находим строку с индексом $index
preg_match("|^[\d]+|", $line, $matches);
if(isset($matches)) $index[]=$matches[0];
}
//находим максимальное значение массива
//$index и увеличиваем его на единицу
echo max($index)+1;
?>
В окне веб-браузера это будет выглядеть примерно ТАК.
Примечание.При таком подходе при увеличении объема файла время на поиск максимального значения будет расти, поэтому целесообразно хранить максимальный индекс в отдельном файле, переписывая его при каждом добавлении уникального индекса в файл.
Теперь, когда новый уникальный индекс получен, можно добавить новую запись в файл.
<?php
//имя файла
$filename="index.txt";
//открываем файл для записи
$fd=fopen($filename, "a");
//добавляем новую запись
fwrite($fd, "5 Новая строка\n");
//закрываем файл
fclose($fd);
?>
В конце строки следует поместить символ перевода строки \n, иначе новая запись окажется не на новой строке, а в конце последней записи. После работы функции будет добавлена новая строка, в результате чего файл index.txt примет вид:
1 Программирование
2 Программирование на РНР
3 Программирование на JavaScript
4 Программирование на ASP.NET
5 Новая строка
Еще одной интересной задачей является редактирование отдельных записей файла. Эту задачу решает небольшое веб-приложение, расположенное в файле edit.php, код которого расположен ниже.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Файл edit.php</title>
</head>
<body>
<?php
//edit.php
//имя файла
$filename="index.txt";
//если передано исправленное содержимое файла,
//открываем файл и перезаписываем его
if(isset($_POST['content']))
{
//открываем файл для чтения
$fd=@fopen($filename, "r");
//читаем содержимое буфера в переменную $bufer
$bufer=fread($fd, filesize($filename));
//закрываем файл
fclose($fd);
//изменяем строку с индексом $_POST['index']
$parent="|".$_POST['index']."[^\n]*\n|";
$replacement=$_POST['content'];
$bufer=preg_replace($parent, $replacement, $bufer);
//открываем файл для записи
$fd=@fopen($filename, "w");
//перезаписываем содержимое файла
fwrite($fd, $bufer);
//закрываем файл
fclose($fd);
//помещаем в суперглобальный массив $_GET имя файла
$_GET['index']=$_POST['index'];
}
?>
<form action="edit.php" method="get" name="first">
Номер записи <br>
<input name="index" type="text" value="<?php echo $_GET['index'];?>" size="25">
<br>
<input name="" type="submit" value="Отправить">
</form>
<?php
//если строке запроса передан индекс,
//открываем его для редактирования
if(isset($_GET['index']))
{
//помещаем содержимое файла в массив $lines
$lines=file($filename);
if($_GET['index']<1 || $_GET['index']>count($lines))
{
exit("К сожалению такая запись не существует");
}
?>
<form action="edit.php" method="post" name="stcond">
<textarea name="content" cols="50" rows="10">
<?php echo $lines[$_GET['index']-1]; ?>
</textarea><br>
<input name="index" type="hidden" value="<?php echo $_GET['index'];?>">
<input name="edit" type="submit" value="Редактировать">
</form>
<?php
}
?>
</body>
</html>
В скрипте определяются две формы, первая их которых, first, содержит текстовое поле index для номера записи из файла index.txt и кнопку для отправки данных обработчику, в качестве которого выступает этот же самый скрипт. Форма будет выглядеть так:
После ввода в форму номера записи страница перезагружается, и обработчик, следующий сразу за формой, помещает содержимое файла в массив $lines. Если массив содержит элемент с индексом, переданным из первой формы, то происходит вывод второй формы stcond, содержащей текстовую область для редактирования записи.
Кроме того, форма имеет скрытое поле index, через которое передается индекс редактируемой записи.
После редактирования содержимого записи данные повторно отправляются скрипту в файле edit.php, но уже методом POST. В дело вступает обработчик, расположенный в начале файла. Он помещает содержимое редактируемого файла во временную переменную $bufer, содержимое которой редактируется при помощи функции preg_replace(). После того как содержимое файла исправлено в переменной $bufer, происходит перезапись файла ее содержимым.
Последняя задача, которая может быть полезна при работе с индексными файлами — удаление записи с определенным индексом. Данная задача решается при помощи скрипта, представленного ниже.
<?php
//индекс строки
$index=2;
//имя файла
$filename="index.txt";
//открываем файл для чтения
$fd=fopen($filename, "r");
//читаем содержимое файла
$bufer=fread($fd, filesize($filename));
//закрываем файл
fclose($fd);
//удаляем строку с индексом $index
$bufer=preg_replace("|$index [^\n]*\n|", "", $bufer);
//открываем файл для записи
$fd=fopen($filename, "w");
//перезаписываем содержимое файла
fwrite($fd, $bufer);
//закрываем файл
fclose($fd);
?>
В результате работы скрипта содержимое файла index.txt изменится следующим образом:
1 Программирование
3 Программирование на JavaScript
4 Программирование на ASP.NET
5 Новая строка
Рассмотренные выше скрипты осуществляют запись в файл в предположении, что скрипт владеет файлом единолично, но при записи в файл одновременно несколькими пользователями могут возникнуть конфликтные ситуации, приводящие к разрушению информации в файле.
Примечание. На веб-сленге операцию блокировки файла часто называют "залачиванием". Сленговое словечко "залачивать" происходит от английского глагола to lock — закрывать.
В РНР для предотвращения такой ситуации имеется специальная функция flock(), которая блокирует файл, не позволяя другим пользователям читать этот файл или писать в него до тех пор, пока процесс, наложивший блокировку, не закончит работу с файлом. Синтаксис функции flock() следующий:
bool flock(resource fd, int operation [, int &wouldblock])
В качестве первого аргумента функция принимает дескриптор файла, возвращаемый функцией fopen(). В качестве второго аргумента функции передается константа, сообщающая тип операции, совершаемой над файлом. Допустимы следующие значения:
LOCK_SH — чтение файла несколькими потоками;
LOCK_EX — блокировка для использования файла одним потоком(для записи);
LOCK_UN — снятие блокировки с файла, когда оно больше не требуется, чтобы остальные участники могли получить к нему доступ.
Третий необязательный параметр wouldblock устанавливается в true, если файл, к которому происходит обращение, уже блокирован другим скриптом.
Функцию flock() следует вызывать сразу после открытия файла для установки блокировки и непосредственно перед закрытием файла для снятия блокировки.
Пример:
<?php
//имя файла
$filename="index.txt";
//открываем файл для записи
$fd=fopen($filename,"w");
//блокируем файл
flock($fd, LOCK_EX);
//перезаписываем содержимое файла
fwrite($fd, "Текст для записи в файл index.txt");
//снимаем блокировку с файла
flock($fd,LOCK_UN);
//закрываем файл
fclose($fd);
?>
В реальных веб-приложениях необходимы более сложные схемы блокировки файлов. Так при добавлении записи в файловый вариант гостевой книги, чата или счетчика посещений, если файл заблокирован предыдущей операцией, информация будет потеряна, поэтому следует организовать цикл, как это продемонстрировано ниже.
Реализация сложной схемы блокировки
<?php
function work_with_file($filename, $str)
{
//открываем файл
if($fd=@fopen($filename, "a"))
{
//в течении 10 секунд пытаемся получить
//единоличный доступ к файлу
for($i=0; $i<10; ++$i)
{
//как только доступ получен выходим из цикла
if(flock($fd, LOCK_EX)) break;
//задерживаем время выполнения программы на 1секунду,
//если доступ получить не удалось
else sleep(1);
}
//записываем строку в файл
fwrite($fd, $str);
//очищаем буфер записи
flush($fd);
//снимаем блокировку с файла
flock($fd, LOCK_UN);
//закрываем файл
fclose($fd);
//покидаем функцию
return true;
}
else
{
error("Нет доступа к файлу или он не существует!", $file);
return false;
}
}
?>
В данном скрипте представлена функция work_with_file(), которая в качестве первого параметра $filename принимает имя файла, а вкачестве второго параметра $str — информацию, которую необходимо дописать в файл. При этом блокировка файла осуществляется в цикле: при неудачной попытке заблокировать файл происходит задержка выполнения программы с помощью функции sleep(), которая принимает единственный параметр — время— задержки в секундах.
Осуществить упаковку и распаковку соответственно, массивов и объектов позволяют функции serialize() и unserialize().
serialize($obj) — возвращает строку, являющуюся упакованным эквивалентом некоего объекта $obj, переданного в первом параметре. При этом совершенно не важно, что это за объект: массив или целое число ... Да что угодно.
unserialize($str) —принимает в лице своего параметра $str строку, ранее созданную при помощи serialize(), и возвращает целиком объект, который был упакован.
Эти функции удобно использовать при работе с файлами, т.к. упакованный в строку массив нужно где-то хранить.
Использование функции serialize() при работе с файлами
<?php
$poll[0]=23;
$poll[1]=45;
$poll[2]=34;
$poll[3]=2;
$poll[4]=12;
//упаковываем массив в строку
$str=serialize($poll);
//помещаем строку в файл
$fd=fopen("text.txt","w");
//сохраняем в файле упакованный массив
fwrite($fd, $str);
//закрываем файл
fclose($fd);
?>
После того как упакованный массив сохранен в файле, в другом скрипте его можно извлечь при помощи кода, представленного ниже.
Использование функции unserialize() при работе с файлами
<?php
//открываем файл
$fd=fopen("text.txt", "r");
//читаем содержимое файла во временную переменную $bufer
$bufer=fread($fd, filesize("text.txt"));
//закрываем файл
fclose($fd);
//извлекаем массив из переменной $bufer
$arr=unserialize( $bufer);
//выводим дамп массива
print_r($arr);
?>
Для чтения файлов с расширением csv применяется функция fgetcsv().
Формат CSV является одним из форматов, в котором можно сохранять файлы MS Excel. Ниже приведен пример чтения созданного MS Excel файла file.csv, содержащего пароли пользователей.
Чтение csv - файла
<?php
//имя файла
$filename="file.csv";
//открываем файл
$fd=fopen("file.csv", "r");
//в цикле читаем строки файла
while($data=fgetcsv($fd, 1000, ";"))
{
foreach($data as $element) echo "$element ";
echo "<br>";
}
//закрываем файл
fclose($fd);
?>
В окне веб-браузера это будет выглядеть примерно ТАК.
Похожие материалы по теме: Запись в файл. Закрытие файла. Считывание из файла