Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка PHP 2008.doc
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
1 Мб
Скачать
☆

Тема 10 Работа с файлами и каталогами,

запуск внешних программ

10.1 Функции работы с файлами

10.2 Блокирование файла

10.3 Функции работы с каталогами

10.4 Запуск внешних программ

10.1 Функции работы с файлами

При работе с файлами интерпретатору PHP все равно, какие слэши использовать: прямые или обратные. Он в любом случае переведет их в ту форму, которая требуется ОС, а функции по работе с полными именами файлов также не будут против «чужих» слэшей.

Можно работать с файлами на удаленных серверах Web в точности так же, как и со своими собственными. Если имени файлу предшествует строка http:// или ftp://, то PHP понимает, что нужно установить сетевое соединение и работать именно с ним, а не с файлом. При этом в программе такой файл ничем не отличается от обычного.

Текстовые и бинарные файлы. Во многих языках программирования для работы с текстовыми файлами применяется некоторый трюк. В Unix-системах для отделения одной строки файла от другой используется один специальный символ – его принято обозначать \n.

Здесь \n обозначает именно один символ, т. е., один байт. Когда PHP встречает комбинацию \n в строке (например, «это \n тест»), он воспринимает ее как один байт. В то же время, в строке, заключенной в апострофы, комбинация \n не имеет никакого специального назначения и обозначает буквально «символ \, за которым идет символ n».

В Windows для разделения строк применяется не один, а два символа, следующих подряд, – \r\n. Для того чтобы языки программирования были лучше переносимы с одной операционной системы на другую, при чтении текстовых файлов комбинация \r\n преобразуется «на лету» в один символ \n, так что программа и не замечает, что формат файла не такой, как в Unix. Поэтому, если например, прочитать содержимое всего текстового файла в строку, то длина такой строки окажется меньше физического размера файла – ведь из нее «съелись» некоторые символы \r. Это относится к системе Windows. При записи строки в текстовый файл происходит в точности наоборот: один \n становится на диске парой \r\n.

Практически во всех языках программирования можно отключить режим автоматической трансляции \r\n в один \n. Обычно для этого используется вызов специальной функции, который говорит, что для указанного файла нужно применять бинарный режим ввода/вывода, когда все байты читаются, как есть.

Так как PHP был написан целиком на Си, а Си использует трансляцию символов перевода строк, то описанная техника работает и в PHP. Однако есть один очень опасный момент. Интерпретатор может работать с файлами в режиме трансляции символа перевода строки. Если файл открыт в режиме бинарного чтения/записи, то PHP все равно, что читается или пишется. Можно считать содержимое бинарного файла (например, GIF-рисунка) в обычную строковую переменную, а потом записать эту строку в другой файл, и при этом информация нисколько не исказится. При чтении текстового файла в Windows получите символы \r\n в конце строки вместо одного \n.

Открытие файла. Работа с файлами в PHP разделяется на три этапа. Сначала файл открывается в нужном режиме, при этом возвращается целое число, служащее идентификатором открытого файла (дескриптор файла). Затем используются команды работы с файлом (чтение или запись, или и то и другое), причем они «привязаны» уже к дескриптору файла, а не к его имени. После этого файл лучше всего закрыть (хотя это можно и не делать, поскольку PHP автоматически закрывает все файлы по завершении сценария).

  • int fopen (string $filename, string $mode, bool $use_include_path=false)

Функиця открывает файл с именем $filename в режиме $mode и возвращает дескриптор открытого файла. В случае ошибки функция возвращает false. Дескриптор 0 в системе соответствует стандартному потоку ввода, он никогда не будет открыт функцией fopen() (во всяком случае, пока не будет закрыт нулевой дескриптор). Необязательный параметр $use_include_path говорит PHP о том, что, если задано относительное имя файла, его следует искать также и в списке путей, используемом инструкциями include и require. Обычно этот параметр не используют. Параметр $mode может принимать следующие значения:

r – файл открывается только для чтения. Если файла не существует, вызов регистрирует ошибку. После удачного открытия указатель файла устанавливается на его первый байт, т. е. на начало;

r+ – файл открывается одновременно на чтение и запись. Указатель текущей позиции устанавливается на его первый байт. Если файла не существует, возвращается false. Если в момент записи указатель файла установлен где-то в середине файла, то данные запишутся прямо поверх уже имеющихся, а не «раздвинут» их, при необходимости увеличив размер файла.

w – создает новый пустой файл. Если на момент вызова уже был файл с таким именем, то он предварительно уничтожается.

w+ – аналогичен r+, но если файла не существовало, создает его. После этого с файлом можно работать как в режиме чтения, так и записи. Если файл существовал до момента вызова, его содержимое удаляется;

a – открывает существующий файл в режиме записи, и при этом сдвигает указатель текущей позиции за последний байт файла. Этот режим используется для дополнения файла.

a+ – открывает файл в режиме чтения и записи, указатель файла устанавливается на конец файла, при этом содержимое файла не уничтожается. Отличается от a тем, что если файла изначально не существовало, то он создается. Этот режим полезен, если нужно что-то дописать в файл, но неизвестно, создан ли уже такой файл;

В конце любой из строк r, w, a, r+, w+ и a+ может находиться еще один необязательный символ – b или t. Если указан b (или не указан вообще никакой), то файл открывается в режиме бинарного чтения/записи. Если же это t, то для файла устанавливается режим трансляции символа перевода строки, т. е. он воспринимается как текстовый.

Пример работы с текстовыми файлами:

<?

// Получает в параметрах строку и возвращает через пробел коды

// символов, из которых она состоит

function MakeHex($st)

{ for($i=0; $i<strlen($st); $i++)

$Hex[]=sprintf("%2X",ord($st[$i]));

return join(" ",$Hex);

}

// Открываем файл разными способами

$f=fopen("test.php","r"); // бинарный режим

echo MakeHex(fgets($f,100)),"<br>\n";

$f=fopen("test.php","rt"); // текстовый режим

echo MakeHex(fgets($f,100)),"<br>\n";

?>

Первая строчка файла test.php состоит всего из двух символов – это < и ?. За ними должен следовать маркер конца строки. Сценарий показывает, как выглядит этот маркер, т. е. состоит ли он из одного или двух символов. Результат работы сценария:

3C 3F 0D 0A

3C 3F 0A

Бинарное и текстовое чтение дали разные результаты! В последнем случае произошла трансляция маркера конца строки.

Можно предварять имя файла строкой http:// или ftp://, при этом будет осуществляться доступ к файлу с удаленного хоста. В случае HTTP-доступа PHP открывает соединение с указанным сервером, а также посылает ему нужные заголовки: Host и GET. После чего при помощи файлового дескриптора из удаленного файла можно читать обычным образом, например с помощью функции fgets().

Если открывается FTP-файл, то в него можно производить либо запись, либо читать из него, но не и то и другое одновременно. Кроме того, лучше не использовать обратные слэши \ в именах файлов. При использовании обратного слэша нужно его удвоить, потому что в строках он воспринимается как спецсимвол:

$fp = fopen ("c:\\windows\\hosts", "r");

Этот способ не переносим между операционными системами. Лучше не использовать его! Примеры:

// Открывает файл на чтение

$f=fopen("/home/file.txt","r")or die("Ошибка!");

// Открывает HTTP-соединение на чтение

$f=fopen("http://www.php/","r") or die("Ошибка!");

// Открывает FTP-соединение с указанием логина и пароля для записи

$f = fopen("ftp://user:password@example.com/", "w")

or die("Ошибка!");

Конструкция or die(). Эта конструкция применяется при работе с файлами. Оператор or имеет очень низкий приоритет (даже ниже, чем у =), поэтому всегда выполняется уже после присваивания.

Если файл открыть не удалось, fopen() возвращает false, а значит, осуществляется вызов функции die(). Нельзя просто заменить or на, казалось бы равнозначный ему оператор ||, потому что последний имеет гораздо более высокий приоритет – выше, чем у =. Таким образом, в результате вызова функции

$f=fopen("/home/file.txt", "r") || die("Ошибка!");

в действительности будет выполнено

$f=(fopen("/home/file.txt","r") || die("Ошибка!"));

Это не совсем то, что нам нужно.

Безымянные временные файлы. Иногда приходится работать с временными файлами, которые при завершении программы хотелось бы удалить. При нужно знать лишь файловый дескриптор, а не имя временного файла. Для создания таких объектов в PHP предусмотрена специальная функция.

  • int tmpfile()

Создает новый файл с уникальным именем и открывает его на чтение и запись. В дальнейшем вся работа должна вестись с возвращенным файловым дескриптором, потому что имя файла недоступно. Пространство, занимаемое временным файлом, автоматически освобождается при его закрытии и при завершении работы программы.

Закрытие файла. После работы файл лучше всего закрыть (несмотря на то, что PHP сам закрывает все файлы по завершении работы сценария). Для этого используется следующая функция:

  • int fclose(int $fp)

Функция закрывает файл и возвращает false, если файл закрыть не удалось. В противном случае возвращает значение «истина».

Необходимо всегда закрывать FTP- и HTTP-соединения, потому что в противном случае «беспризорный» файл приведет к неоправданному простою канала и излишней загрузке сервера. Кроме того, успешно закрыв соединение, можно быть уверены в том, что все данные были доставлены без ошибок.

Особенно своевременное закрытие критично при использовании FTP-файла в режиме записи, когда вывод программы для ускорения буферизуется. Не закрыв файл, вообще нельзя быть увереным, что буфер вывода очистился, а значит, файл записался на удаленную машину верно.

Чтение и запись. Для каждого открытого файла (точнее, для каждого файлового дескриптора, ведь один и тот же файл может быть открыт несколько раз, т. е. с ним может быть связано сразу несколько дескрипторов) система хранит определенную величину, которая называется текущей позицией ввода-вывода, или указатель файла. Функции чтения и записи файлов работают именно с этой позицией. А именно, функции чтения читают блок данных, начиная с этой позиции, а функции записи – записывают, также отсчитывая от нее. Если указатель файла установлен за последним байтом и осуществляется запись, то файл автоматически увеличивается в размере. После того как файл успешно открыт, из него (при помощи дескриптора файла) можно читать, а также, при соответствующем режиме открытия, писать. Обмен данными осуществляется через строки, начиная с позиции указателя файла.

Блочные чтение/запись.

  • string fread(int $f, int $numbytes)

Читает из файла $f $numbytes символов и возвращает строку этих символов. После чтения указатель файла продвигается к следующим после прочитанного блока позициям. Если $numbytes больше, чем можно прочитать из файла (например, раньше достигается конец файла), возвращается то, что удалось считать. Этот прием можно использовать, если нужно считать в строку файл целиком. Для этого нужно задайть в $numbytes очень большое число (например, сто тысяч). Но нужно заботиться об экономии памяти в системе, так поступать не рекомендуется, потому что в некоторых версиях PHP передача большой длины строки во втором параметре fread() вызывает первоначальное выделение этой памяти в соответствии с запросом (даже если строка гораздо короче). Конечно, потом лишняя память освобождается, но все же ее может и не хватить для начального выделения.

  • int fwrite(int $f, string $st)

Записывает в файл $f все содержимое строки $st. При работе с текстовыми файлами все \n автоматически преобразуются в тот разделитель строк, который принят в операционной системе.

Построчные чтение/запись.

  • string fgets(int $f, int $length)

Читает из файла одну строку, заканчивающуюся символом новой строки \n. Этот символ также считывается и включается в результат. Если строка в файле занимает больше $length-1 байтов, то возвращаются только ее $length-1 символов.

  • int fputs(int $f, string $st)

Эта функция – полный аналог fwrite().

Чтение CSV-файла.

  • list fgetcsv(int $f, int $length,

char $delim=’,’)

Функция читает одну строку из файла Excel, записанного в формате csv, заданного дескриптором $f, и разбивает ее по символу $delim. Параметр $delim должен быть строкой из одного символа, в противном случае принимается во внимание только первый символ этой строки. Функция возвращает получившийся список или false, если строки кончились. Параметр $length задает максимальную длину строки точно так же. Пустые строки в файле не игнорируются, а возвращаются как список из одного элемента – пустой строки.

Пример использования функции:

$f=fopen("file.csv","r") or die("Ошибка!");

for($i=0; $data=fgetcsv($f, 1000, ";"); $i++) {

$num = count($data);

if($num==1 && $data[0]==="") continue;

echo "<h3>Строка номер $i ($num полей):</h3>";

for($c=0; $c<$num; $c++)

print "[$c]: $data[$c]<br>";

}

fclose($f);

Положение указателя текущей позиции.

  • int feof(int $f)

Функция возвращает true, если достигнут конец файла. Эта функция чаще всего используется в следующем контексте:

$f=fopen(: "myfile.txt","r");

while(!feof($f))

{ $st=fgets($f);

// обрабатываем очередную строку $st

// . . .

}

fclose($f);

Лучше избегать подобных конструкций, т. к. в случае больших файлов они довольно медлительны. Лучше читать файл целиком при помощи File() или fread(), если нужен доступ к каждой строке этого файла, а не только к нескольким первым!

  • int fseek(int $f, in $offset,

int $whence=SEEK_SET)

Устанавливает указатель файла на байт со смещением $offset (от начала файла, от его конца или от текущей позиции, в зависимости от параметра $whence). Эта функция может не сработать, если дескриптор $f ассоциирован не с обычным локальным файлом, а с соединением HTTP или FTP. Параметр $whence задает, с какого места отсчитывается смещение $offset. В PHP для этого существуют три константы, равные, соответственно, 0, 1 и 2: SEEK_SET – устанавливает позицию начиная с начала файла; SEEK_CUR – отсчитывает позицию относительно текущей позиции; SEEK_END – отсчитывает позицию относительно конца файла. В случае использования последних двух констант параметр $offset может быть отрицательным (а при применении SEEK_END он будет отрицательным наверняка). В случае успешного завершения функция возвращает 0, а в случае неудачи  1.

  • int ftell(int $f)

Возвращает положение указателя файла.

Функции для определения типов файлов. PHP имеет набор вспомогательных функций для работы с файлами. Они отличаются тем, что работают не с файловыми идентификаторами, а непосредственно с их именами.

Определение типа файла

  • bool file_exists(string $filename)

Возвращает true, если файл с именем $filename существует на момент вызова.

  • string filetype(string $filename)

Возвращает строку, которая описывает тип файла с именем $filename. Если такого файла не существует, возвращает false. После вызова строка будет содержать одно из следующих значений: file – обычный файл; dir – каталог; link – символическая ссылка; fifo – fifo-канал; block – блочно-ориентированное устройство; char – символьно-ориентированное устройство; unknown – неизвестный тип файла.

  • bool is_file(string $filename)

Возвращает true, если $filename – обычный файл.

  • bool is_dir(string $filename)

Возвращает true, если $filename – каталог.

  • bool is_link(string $filename)

Возвращает true, если $filename – символическая ссылка.

Определение возможности доступа.

  • bool is_readable(string $filename)

Возвращает true, если файл может быть открыт для чтения.

  • bool is_writeable(string $filename)

Возвращает true, если в файл можно писать.

  • bool is_executable(string $filename)

Возвращает true, если файл – исполняемый.

Определение параметров файла.

  • array stat(string $filename)

Функция собирает вместе всю информацию, выдаваемую операционной системой для указанного файла, и возвращает ее в виде массива. Этот массив всегда содержит следующие элементы с указанными ключами: 0 – устройство; 1 – номер узла inode; 2 – атрибуты защиты файла; 3 – число синонимов («жестких» ссылок) файла; 4 – идентификатор uid владельца; 5 – идентификатор gid группы; 6 – тип устройства; 7 – размер файла в байтах; 8 – время последнего доступа в секундах, прошедших с 1 января 1970 года; 9 – время последней модификации содержимого файла; 10 – время последнего изменения атрибутов файла; 11 – размер блока; 12 – число занятых блоков.

Специализированные функции.

Для того чтобы каждый раз не возиться с вызовом stat() и разбором выданного массива, разработчики PHP предусмотрели несколько простых функций, которые сразу возвращают какой-то один параметр файла. Кроме того, если объекта (обычно файла), для которого вызвана какая-либо из ниже перечисленных функций, не существует, эта функция возвратит false.

  • int fileatime(string $filename)

Возвращает время последнего доступа к файлу. Время выражается в количестве секунд, прошедших с 1 января 1970 года. Если файл не обнаружен, возвращает false.

  • int filemtime(string $filename)

Возвращает время последнего изменения файла или false в случае отсутствия файла.

  • int filectime(string $filename)

Возвращает время создания файла.

  • int filesize(string $filename)

Возвращает размер файла в байтах или false, если файла не существует.

  • int touch(string $filename [, int $timestamp])

Устанавливает время модификации указанного файла $filename равным $timestamp (в секундах, прошедших с 1 января 1970 года). Если второй параметр не указан, то подразумевается текущее время. В случае ошибки возвращается false.

Функции для работы с именами файлов:

  • string basename(string $path)

Выделяет основное имя файла из пути $path. Примеры:

echo basename("/home/somebody/somefile.txt");

// выводит "somefile.txt"

echo basename("/"); // ничего не выводит

echo basename("/."); // выводит "."

echo basename("/./"); // также выводит "."

Функция basename() (и все последующие) не проверяет существование файла. Она берет часть строки после самого правого слэша и возвращает ее. Функция basename() правильно обрабатывает как прямые, так и обратные слэши.

  • string dirname(string $path)

Возвращает имя каталога, выделенное из пути $path. Функция умеет обрабатывать нетривиальные ситуации:

echo dirname("/home/file.txt"); // выводит "/home"

echo dirname("../file.txt"); // выводит ".."

echo dirname("/file.txt");

// выводит "/" под Unix, "\" под Windows

echo dirname("/"); // то же самое

echo dirname("file.txt"); // выводит "."

Если функции dirname() передать «чистое» имя файла, она вернет ".", что означает «текущий каталог».

  • string tempnam(string $dir, string $prefix)

Генерирует имя файла в каталоге $dir с префиксом $prefix в имени, причем так, чтобы созданный под этим именем в будущем файл был уникален. Для этого к строке $prefix присоединяется некое случайное число. Например, вызов tempnam("/tmp","temp") может возвратить что-то типа /tmp/temp3a6b243c. Если такое имя нужно создать в текущем каталоге, нужно передать $dir=".".

  • string realpath(string $path)

Функция преобразовает относительный путь в $path в абсолютный, т. е. начинающийся от корня. Например:

echo realpath("../t.php");

// абсолютный путь – например, /home/test.php

echo realpath("."); // выводит имя текущего каталога

Файл, который указывается в параметре $path, должен существовать, иначе функция возвращает false.

Функции манипулирования целыми файлами:

  • bool copy(string $src, string $dst)

Копирует файл с именем $src в файл с именем $dst. Если файл $dst на момент вызова существовал, осуществляется его перезапись. Функция возвращает true, если копирование прошло успешно, а в случае провала – false.

  • bool rename(string $oldname, string $newname)

Переименовывает (или перемещает) файл с именем $oldname в файл с именем $newname. Если файл $newname уже существует, функция возвращает false. В случве успеха, возвращается true.

  • bool unlink(string $filename)

Удаляет файл с именем $filename. В случае неудачи возвращает false, иначе – true.

  • list File(string $filename)

Считывает файл с именем $filename целиком и возвращает массив-список, каждый элемент которого соответствует строке в прочитанном файле. Функция работает очень быстро – гораздо быстрее использование fopen() и чтение файла по одной строке. Неудобство этой функции состоит в том, что символы конца строки (обычно \n), не вырезаются из строк файла, а также не транслируются, как это делается для текстовых файлов.

  • array get_meta_tags(string $filename, int $use_include_path=false);

Функция открывает файл и ищет в нем все тэги <meta> до тех пор, пока не встретится закрывающий тэг </head>. Если очередной тэг <meta> имеет вид:

<meta name="название" content="содержимое">

то пара название=>содержимое добавляется в результирующий массив, который под и возвращается. Функцию удобно использовать для быстрого получения всех метатегов из указанного файла. Если необязательный параметр $use_include_path установлен, то поиск файла осуществляется не только в текущем каталоге, но и во всех тех, которые назначены для поиска инструкциями include и require.

Другие функции:

  • bool ftruncate(int $f, int $newsize)

Функция усекает открытый файл $f до размера $newsize. Файл должен быть открыт в режиме, разрешающем запись. Пример:

ftruncate($f,0); // очистить содержимое файла

  • void fflush(int $f)

Функция заставляет PHP немедленно записать на диск все изменения, которые производились до этого с открытым файлом $f. Для повышения производительности все операции записи в файл буферизируются: например, вызов fputs($f,"Это строка!") не приводит к непосредственной записи данных на диск – сначала они попадают во внутренний буфер (обычно размером 8K). Как только буфер заполняется, его содержимое отправляется на диск, а сам он очищается, и все повторяется вновь. Особенный выигрыш от буферизации чувствуется в сетевых операциях, когда просто глупо отправлять данные маленькими порциями. Функция fflush() вызывается неявно и при закрытии файла.

  • int set_file_buffer(int $f, int $size)

Функция устанавливает размер буфера для указанного открытого файла $f. Чаще всего она используется так:

set_file_buffer($f,0);

Приведенный код отключает буферизацию для указанного файла, так что теперь все данные, записываемые в файл, немедленно отправляются на диск или в сеть.