- •Тема 1 Основы cgi-программирования
- •1.1 Методы передачи данных
- •1.2 Передача документа пользователю
- •1.3 Передача информации cgi-сценарию
- •Тема 2 Характеристика языка php
- •2.1 Принцип работы php
- •2.2 Переменные, константы, выражения
- •Тема 3 Работа с данными формы
- •3.1 Передача данных
- •3.2 Трансляция полей формы в переменные
- •Тема 4 Конструкции языка
- •4.1 Условные инструкции
- •4.2 Инструкции циклов
- •4.3 Инструкции включения
- •Тема 5 Ассоциативные массивы
- •5.1 Списки и ассоциативные массивы
- •5.2 Операции над массивами
- •5.3 Списки и строки
- •5.4 Сериализация
- •Тема 6 Работа с массивами
- •6.1 Сортировка массивов
- •6.2 Функции для работы с массивами
- •Тема 7 Функции и области видимости
- •7.1 Формат определения функции, передача параметров
- •7.2 Глобальные, локальные, статические переменные
- •7.3 Рекурсия, вложенные и условно-определяемые функции
- •7.4 Передача функций по ссылке и возврат функцией ссылки
- •Тема 8 Строковые функции
- •8.1 Функции работы со строками
- •8.2 Работа с блоками текста
- •Тема 9 Математические функции
- •9.1 Встроенные константы
- •9.2 Встроенные функции
- •Тема 10 Работа с файлами и каталогами,
- •10.1 Функции работы с файлами
- •10.2 Блокирование файла
- •10.3 Функции работы с каталогами
- •10.4 Запуск внешних программ
- •Тема 11 Работа с датами и временем,
- •11.1 Представление времени в формате timestamp
- •11.2 Работа с датами, григорианский календарь
- •11.3 Посылка писем через php
- •Тема 12 Работа с www
- •12.1 Установка заголовков ответа
- •12.2 Работа с Cookies
- •Тема 13 Управление интерпретатором
- •13.1 Управление интерпретатором
- •13.2 Управление сессиями
- •Тема 14 Работа с базой данных mysql
- •14.1 Соединение с базой данных
- •14.2 Выполнение запросов к базе данных
- •Тема 15 Загрузка файлов на сервер
- •15.1 Multipart-формы, тег выбора файла
- •15.2 Поддержка закачки в php
- •Учебное издание
- •Разработка программного обеспечения на платформе net: php.Net
- •246019 Г. Гомель, ул. Советская, 104
Тема 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);
Приведенный код отключает буферизацию для указанного файла, так что теперь все данные, записываемые в файл, немедленно отправляются на диск или в сеть.
