На главную Назад
Добро пожаловать, уважаемый посетитель!

 

ГЛАВА 7

Файловый ввод/вывод и файловая система

Данная главапосвящена одному из важнейших аспектов РНР- средствам файлового ввода/вывода. Какнетрудно предположить, входные и выходныепотоки данных интенсивно используются приразработке web-приложений. Не ограничиваясьпростым чтением/записью файлов, РНРпредоставляет в распоряжение программистасредства просмотра и модификации сервернойинформации, а также запуска внешнихпрограмм. Этим средствам и посвященанастоящая глава.

Проверкасуществования и размера файла

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

file_exists( ) и is_file( ).

file_exists( )

Функция filе_ехists ( ) проверяет, существует ли заданныйфайл. Если файл существует, функциявозвращает TRUE, в противном случаевозвращается FALSE. Синтаксис функции file_exists():

bool file_exists(string файл)

Примерпроверки существования файла:

if (! file_exists ($filename)):

print "File$filename does not exist!";

endif:

is_file( )

Функция is_file()проверяет существование заданного файла ивозможность выполнения с ним операцийчтения/записи. В сущности, is_file( )представляет собой более надежную версиюfile_exists( ), которая проверяет не только фактсуществования файла, но и то, поддерживаетли он чтение и запись данных:

bool is_file(string файл)

Следующийпример показывает, как убедиться всуществовании файла и возможностивыполнения операций с ним:

$file = "somefile.txt";

if (is_file($file)) :

print "The file$file is valid and exists!";

else :

print "The file$file does not exist or it is not a valid file!";

endif:

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

filesize( )

Функция filesize()возвращает размер (в байтах) файла сзаданным именем или FALSE в случае ошибки.Синтаксис функции filesize( ):

int filesize(string имя_файла)

Предположим,вы хотите определить размер файла pastry.txt.Для получения нужной информации можновоспользоваться функцией filesize( ):

$fs = filesize("pastry.txt");print "Pastry.txt is $fs bytes.";

Выводитсяследующий результат:

Pastry.txt is 179 bytes.

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

Открытие изакрытие файлов

Прежде чемвыполнять операции ввода/вывода с файлом,необходимо открыть его функцией fopen( ).

fopen( )

Функцияfopen( ) открывает файл (если он существует) ивозвращает целое число - так называемый файловыйманипулятор (file handle).Синтаксис функции fopen( ):

int fopen (string файл,string режим [, int включение_пути])

Открываемыйфайл может находиться в локальной файловойсистеме, существовать в виде стандартногопотока ввода/вывода или представлять файл вудаленной системе, принимаемой средствамиHTTP или FTP.

Параметрфайл может задаваться в нескольких формах,перечисленных ниже:

Еслипараметр содержит имя локального файла,функция fopen( ) открывает этот файл ивозвращает манипулятор.

Еслипараметр задан в виде php://stdin, php://stdout или php://stderr,открывается соответствующий стандартныйпоток ввода/вывода.

Еслипараметр начинается с префикса http://,функция открывает подключение HTTP к серверуи возвращает манипулятор для указанногофайла.

Еслипараметр начинается с префикса ftp://, функцияоткрывает подключение FTP к серверу ивозвращает манипулятор для указанногофайла. В этом случае следует обратитьособое внимание на два обстоятельства: еслисервер не поддерживает пассивный режим FTP,вызов fopen( ) завершается неудачей. Более того,FTP-файлы открываются либо для чтения, либодля записи.

Приработе в пассивном режиме сервер ЯР ожидаетподключения со стороны клиентов. Приработе в активном режиме сервер самустанавливает соединение с клиентом. Поумолчанию обычно используется активныйрежим.

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

Таблица7.1. Режимыоткрытия файла 

РежимОписание

r

Толькочтение. Указатель текущей позицииустанавливается в начало файла
r+ Чтение изапись. Указатель текущей позицииустанавливается в начало файла
wТолькозапись. Указатель текущей позицииустанавливается в начало файла, а всесодержимое файла уничтожается. Еслифайл не существует, функция пытаетсясоздать его
w+Чтение и запись. Указатель текущей позицииустанавливается в начало файла, а всесодержимое файла уничтожается. Если файл несуществует, функция пытается создать его 
aТолько запись. Указатель текущей позицииустанавливается в конец файла. Если файлнесуществует, функция пытается создать его
a+Чтение изапись. Указатель текущей позицииустанавливается в конец файла. Если файл несуществует, функция пытается создать его

Еслинеобязательный третий параметр включение_путиравен 1, то путь к файлу определяется поотношению к каталогу включаемых файлов,указанному в файле php.ini (см. главу 1).

Нижеприведен пример открытия файла функцией fopen().Вызов die( ), используемый в сочетании с fopen( ),обеспечивает вывод сообщения об ошибке втом случае, если открыть файл не удастся:

$file = "userdata.txt";// Некоторый файл

$fh = fopen($file,"a+") or die("File ($file) does not exist!");

Следующийфрагмент открывает подключение к сайту РНР(http://www.php.net):

$site = "http://www.php.net":// Сервер, доступный через HTTP

$sh = fopen($site.,"r");     //Связать манипулятор с индекснойстраницей Php.net

Послезавершения работы файл всегда следуетзакрывать функцией fclose( ).

fclose ( )

Функцияfclose( ) закрывает файл с заданнымманипулятором. При успешном закрытиивозвращается TRUE, при неудаче - FALSE.Синтаксис функции fclose( ):

int fclose(int манипулятор)

Функция fclose() успешно закрывает только те файлы, которыебыли ранее открыты функциями fopen( ) или fsockopen(). Пример закрытия файла:

$file = "userdata.txt";

if (file_exists($file)) :

$fh = fopen($file,"r");

// Выполнитьоперации с файлом

fclose($fh);

else :

print "File Sfiledoes not exist!";

endif;

Запись вфайл

С открытымифайлами выполняются две основные операции- чтение и запись.

is_writeable( )

Функцияis_writeable( ) позволяет убедиться в том, что файлсуществует и для него разрешена операциязаписи. Возможность записи проверяется какдля файла, так и для каталога. Синтаксисфункции is_writeable( ):

bool is_writeable (string файл)

Одно важноеобстоятельство: скорее всего, РНР будетработать под идентификатором пользователя,используемым web-сервером (как правило, ).Пример использования is_writeable( ) приведен вописании функции fwrite( ).

fwrite ( )

Функцияfwrite( ) записывает содержимое строковойпеременной в файл, заданный файловымманипулятором. Синтаксис функции fwrite( ):

int fwrite(int манипулятор, stringпеременная [, int длина])

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

<?

// Информацияо трафике на пользовательском сайте

$data ="08:13:00|12:37:12|208.247.106.187|Win98";

$filename = "somefile.txt";

// Если файлсуществует и в него возможна запись

if ( is_writeable($filename)) :

// Открытьфайл и установить указатель текущейпозиции в конец файла

$fh = fopen($filename,"a+");

// Записатьсодержимое $data в файл

$success - fwrite($fh,$data);

// Закрытьфайл

fclose($fh); else :

print "Could notopen Sfilename for writing";

endif;

?>

Функцияfputs( ) является псевдонимом fwrite( ) и можетиспользоваться всюду, где используется fwrite().

fputs( )

Функцияfputs( ) является псевдонимом fwrite( ) и имеетточно такой же синтаксис. Синтаксис функцииfputs( ):

int fputs(int манипулятор,string переменная [, int длина])

Лично япредпочитаю использовать fputs( ). Следуетпомнить, что это всего лишь вопрос стиля,никак не связанный с какими-либо различиямимежду двумя функциями.

Чтение изфайла

Несомненно,чтение является самой главной операцией,выполняемой с файлами. Ниже описанынекоторые функции, повышающиеэффективность чтения из файла. Синтаксисэтих функций практически точно копируетсинтаксис аналогичных функций записи.

is_readable( )

Функция is_readable( ) позволяет убедиться в том, что файлсуществует и для него разрешена операциячтения. Возможность чтения проверяется какдля файла, так и для каталога. Синтаксисфункции is_readable( ):

boo! is_readable (stringфайл]

Скорее всего,РНР будет работать под идентификаторомпользователя, используемым web-сервером (какправило, ), поэтому для того чтобыфункция is_readable( ) возвращала TRUE, чтение изфайла должно быть разрешено всем желающим.Следующий пример показывает, как убедитьсяв том, что файл существует и доступен длячтения:

if ( is_readable($filename)) :

// Открытьфайл и установить указатель текущейпозиции в конец файла

$fh = fopen($filename,"r");

else :

print "$filenameis not readable!";

endif;

fread( )

Функцияfread( ) читает из файла, заданного файловымманипулятором, заданное количество байт.Синтаксис функции fwrite( ):

int fread(int манипулятор,int длина)

Манипулятордолжен ссылаться на открытый файл,доступный для чтения (см. описание функцииis_readable( )). Чтение прекращается послепрочтения заданного количества байт илипри достижении конца файла. Рассмотримтекстовый файл pastry.txt, приведенный влистинге 7.1. Чтение и вывод этого файла вбраузере осуществляется следующимфрагментом:

$fh = fopen('pastry.txt',"r") or die("Can't open file!");

$file = fread($fh,filesize($fh));

print $file;

fclose($fh);

Используяфункцию fllesize( ) для определения размераpastry.txt в байтах, вы гарантируете, что функцияfread( ) прочитает все содержимое файла.

Листинг7.1. Текстовыйфайл pastry.txt

Recipe: Pastry Dough

1 1/4 cups all-purposeflour

3/4 stick (6tablespoons) unsalted butter, chopped

2 tablespoons vegetableshortening 1/4 teaspoon salt

3 tablespoons water

fgetc( )

Функцияfgetc( ) возвращает строку, содержащую одинсимвол из файла в текущей позиции указателя,или FALSE при достижении конца файла.Синтаксис функции fgetc( ):

string fgetc (int манипулятор)

Манипулятордолжен ссылаться на открытый файл,доступный для чтения (см. описание функцииis_readable( ) ранее в этой главе). В следующемпримере продемонстрированы посимвольноечтение и вывод файла с использованиемфункции fgetc( ):

$fh = fopen("pastry.txt","r"); while (! feof($fh)) :

$char = fgetc($fh):

print $char; endwhile;

fclose($fh);

fgets( )

Функцияfgets( ) возвращает строку, прочитанную оттекущей позиции указателя в файле,определяемом файловым манипулятором.Файловый указатель должен ссылаться наоткрытый файл, доступный для чтения (см.описание функции is_readable( ) ранее в этой главе).Синтаксис функции fgets( ):

string fgets (int манипулятор,int длина)

Чтениепрекращается при выполнении одного изследующих условий:

  • из файлапрочитано длина - 1 байт;
  • из файлапрочитан символ новой строки (включается ввозвращаемую строку);
  • из файлапрочитан признак конца файла (EOF).

Если выхотите организовать построчное чтениефайла, передайте во втором параметрезначение, заведомо превышающее количествобайт в строке. Пример построчного чтения ивывода файла:

$fh = fopen("pastry.txt","r");

while (! feof($fh));

$line = fgets($fh,4096);

print $line. "<br>";

endwhile;

fclose($fh):

fgetss( )

Функция fgetss() полностью аналогична fgets( ) за однимисключением - она пытается удалять изпрочитанного текста все теги HTML и РНР:

string fgetss(Int манипулятор, intдлина [, string разрешенные_теги])

Прежде чемпереходить к примерам, ознакомьтесь ссодержимым листинга 7.2 - этот файлиспользуется в листингах 7.3 и 7.4.

Листинг7.2. Файлscience.html

<html>

<head>

<title>BreakingNews - Science</title>

<body>

<h1>Alienlifeform discovered</h1><br>

<b>August 20.2000</b><br>

Early this morning, astrange new form of fungus was found growing in the closet of W. J. Gilmore's old apartmentrefrigerator. It is not known if powerful radiation emanating from the tenant's computermonitor aided in this evolution.

</body>

</html>

Листинг 7.З.Удалениетегов из файла HTML перед отображением вбраузере

<?

$fh = fopen("science.html","r");

while (! feof($fh)) :

print fgetss($fh,2048);

endwhile;

fclose($fh);

?>

Результатприведен ниже. Как видите, из файла science.htmlбыли удалены все теги HTML, что привело кпотере форматирования:

Breaking News - ScienceAlien lifeform discovered August 20. 2000 Early this morning, a strange new formof fungus was found growing in the closet of W. J. Gilmore's old apartmentrefrigerator. It is not known if powerful radiation emanating from the tenant'scomputer monitor aided in this evolution.

В некоторыхситуациях из файла удаляются все теги,кроме некоторых - например, тегов разрывастрок <br>. Листинг 7.4 показывает, как этоделается.

Листинг7.4. Выборочноеудаление тегов из файла HTML

<?

$fh =fopenC'science.html", "r");

$allowable = "<br>";

while (! feof($fh)) :

print fgetss($fh. 2048,$allowable);

endwhile;

fclose($fh);

?>

Результат:

Breaking News - ScienceAlien lifeform discovered August 20. 2000 Early this morning, a strange new formof fungus was found growing in the closet of W. J. Gilmore's old apartmentrefrigerator. It is not known if powerful radiation emanating from the tenant'scomputer monitor aided in this evolution.

Как видите,функция fgetss( ) упрощает преобразованиефайлов, особенно при наличии большогоколичества файлов HTML, отформатированныхсходным образом.

Чтение файлав массив

Функция file( )загружает все содержимое файла виндексируемый массив. Каждый элементмассива соответствует одной строке файла.Синтаксис функции filе ( ):

array file(string файл [, int включение_пути])

Еслинеобязательный третий параметр включение_путиравен 1, то путь к файлу определяется поотношению к каталогу включаемых файлов,указанному в файле php.ini (см. главу 1). Влистинге 7.5 функция file( ) используется длязагрузки файла pastry.txt (см. листинг 7.1).

Листинг7.5. Загрузкафайла pastry.txt функцией file( )

<?

$file_array = file("pastry.txt" );

while ( list( $line_num.$line ) = eacht($file_array ) ):

print "<b>Line$line_num:</b> ", htmlspecialchars($line ), "<br>\n"

endwhile;

?>

Каждаястрока массива выводится вместе с номером:

Line 0: Recipe: PastryDough

Line 1: 1 1/4 cupsall-purpose flour

Line 2: 3/4 stick (6tablespoons) unsalted butter, chopped

Line 3: 2 tablespoonsvegetable shortening

Line 4: 1/4 teaspoonsalt

Line 5: 3 tablespoonswater

Перенаправлениефайла в стандартный выходной поток

Функция readfile() читает содержимое файла и направляет его встандартный вывод (в большинстве случаев -в браузер). Синтаксис функции readfile( ):

int readfile(string файл [, int включение_пути])

Функциявозвращает количество прочитанных байтов.Файл может находиться в локальной файловойсистеме, существовать в виде стандартногопотока ввода/вывода или представлять файл вудаленной системе, принимаемой средствамиHTTP или FTP. Параметр файл задается по тем жеправилам, что и в функции fopen( ).

Предположим,у вас имеется файл latorre.txt, содержимоекоторого вы хотите вывести в браузере:

Restaurant "La Тоrrе." located in Nettuno, Italy, offers an eclectic blend ofstyle. history, and fine seafood cuisine. Within the walls of the medieval borgosurrounding the city, one can dine while watching the passersby shop in thevillage boutiques. Comfort coupled with only the freshest seafare make La Torreone of Italy's finest restaurants.

Привыполнении следующего фрагмента всесодержимое latorre.txt направляется встандартный выходной поток:

<?

$restaurant_file ="latorre.txt";

// Направитьвесь файл в стандартный выходной поток

readfile($restaurant_filе);

?>

Открытиефайлового манипулятора процесса

popen( )

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

int popen (string команда,string режим)

Параметркоманда определяет выполняемую системнуюкоманду, а параметр режим описывает режимдоступа:

<?

// Открытьфайл "spices.txt" для записи

$fh = fopen("spices.txt","w");

// Добавитьнесколько строк текста

fputs($fh, "Parsley,sage, rosemary\n");

fputs($fh, "Paprika,salt, pepper\n");

fputs($fh, "Basil,sage, ginger\n");

// Закрытьманипулятор

fclose($fh);

// Открытьпроцесс UNIX grep для поиска слова Basil в файлеspices.txt

$fh - popen("grepBasil < spices.txt", "r");

// Вывестирезультат работы grep

fpassthru($fh);

?>

Результатвыглядит так:

Basil, sage, ginger

Функцияfpassthru( ) является аналогом функции passthru( ),рассматриваемой в разделе <Запуск внешнихпрограмм> этой главы.

pclose( )

Послевыполнения всех операций файл или процесснеобходимо закрыть. Функция pclose( ) закрываетсоединение с процессом, заданнымманипулятором, по аналогии с тем, какфункция fclose( ) закрывает файл, открытыйфункцией fopen( ). Синтаксис функции pclose( ):

int pclose (int манипулятор}

Впараметре манипулятор передаетсяманипулятор, полученный ранее при успешномвызове рореn( ).

Открытиесоединения через сокет

РНР неограничивается взаимодействием с файлами ипроцессами - вы также можете устанавливатьсоединения через сокеты. Сокет(socket) представляет собойпрограммную абстракцию, позволяющуюустанавливать связь с различными службамидругого компьютера.

fsockopen( )

Функцияfsockopen( ) устанавливает сокетное соединение ссервером в Интернете

черезпротокол TCP или UDP. Синтаксис функции fsockopen( ):

int fsockopen (stringузел, int порт [, int код_ошибки [, string текст_ошибки[, int тайм-аут]]])

Необязательныепараметры код_ошибки и текст_ошибкисодержат информацию, которая будетвыводиться в случае неудачи приподключении к серверу. Оба параметра должныпередаваться по ссылке. Третийнеобязательный параметр, тайм-аут, задаетпродолжительность ожидания ответа отсервера (в секундах). В листинге 7.6продемонстрировано применение функцииfsockopen( ) для получения информации о сервере.Однако перед рассмотрением листинга 7.6необходимо познакомиться еще с однойфункцией - socket_set_blocking( ).

UDP(User Datagram Protocol) - коммуникационный протокол,не ориентированный на соединение.

socket_set_blocking( )

Функцияsocket_set_b1ocki ng( ) позволяет установить контрольнад тайм-аутом для операций с сервером:

socket_set_blocking(int манипулятор,boolean режим)

Параметрманипулятор задает открытый ранее сокет, апараметр режим выбирает режим, в которыйпереключается сокет (TRUE для блокирующегорежима, FALSE для неблокирующего режима).Пример использования функций fsockopen( ) иsocket_set_blocking( ) приведен в листинге 7.6.

Листинг7.6. Использованиефункции fsockopen() для получения информации осервере

<?

function getthehost($host.$path){

// Открыть подключение к узлу

$fp - fsockopen($host,80, &$errno, &$errstr, 30);

// Перейти в блокирующийрежим

socket_set_blocking($fp, 1),

// Отправить заголовки

fputs($fp,"GET $path HTTP/1.1\r\n");

fputs ($fp, "Host:$host\r\n\r\n"); $x = 1;

// Получитьзаголовки

while($x < 10) :

$headers = fgets ($fp,4096);

print $headers;

$x++;

endwhile;

// Закрытьманипулятор

fclose($fp);

}

getthehost("www.apress.com", "/");

?>

В результатевыполнения листинга 7.6 выводится следующийрезультат:

НТТР/1.1 200 OK Server:Microsoft-IIS/4.0 Content-location:

http://www.apress.com/0efault.htmDate: Sat. 19 Aug 2000 23:03:25 GMT

Content-Type: text/htmlAccept-Ranges: bytesLast-Modified: Wed. 19 Jul

2000 20:25:06 GMT ETag:"f0a61666dbff1bf1:34a5" Content-Length: 1311

pfsockopen( )

Функцияpfsockopen( ) представляет собой устойчивую (persistent)версию fsockopen( ). Это означает, что соединениене будет автоматически разорвано позавершении сценария, в котором была вызванафункция. Синтаксис функции pfsockopen( ):

int pfsockopen(string узел, int порт [, int код_ошибки [, string текст _ошибки[, int тайм-аут]]])

Взависимости от конкретных целей вашегоприложения может оказаться удобнееиспользовать pfsockopen( ) вместо fsockopen( ).

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

Сценарии РНРтакже могут выполнять программы,находящиеся на сервере. Такая возможностьособенно часто используется приадминистрировании системы через web-браузер,а также для более удобного получениясводной информации о системе.

ехес( )

Функцияехес( ) запускает заданную программу ивозвращает последнюю строку ее выходныхданных. Синтаксис функции ехес( ):

string exec(string команда [, string массив [, int возврат]])

Обратитевнимание: функция ехес( ) только выполняеткоманду, не выводя результатов ее работы.Все выходные данные команды можносохранить в необязательном параметремассив. Кроме того, если при заданномпараметре массив также задается переменнаявозврат, последней присваивается кодвозврата выполненной команды.

Листинг 7.7показывает, как использовать функцию ехес( )для выполнения системной функции UNIX ping.

Листинг7.7. Проверкасвязи с сервером с применением функции ехес()

<?

exec("ping -с 5www.php.net", $ping);

// В Windows - exec("ping-n 5 www.php.net. $ping);

for ($i=0; $i< count($ping);$i++):

print "<br>$ping[$i]";

endfor;

?>

Результат:

PING www.php.net(208.247.106.187): 56 data bytes

64 bytes from 208.247.106.187: icmp_seq=0 ttl=243time=66.602 ms

64 bytes from 208.247.106.187: icmp_seq=1 ttl=243 time=55.723 ms

64 bytes from 208.247.106.187: icmp_seq=2 ttl=243 time=70.779 ms

64 bytes from208.247.106.187: icmp_seq=3 ttl=243 time=55.339 ms

64 bytes from208.247.106.187: icmp_seq=4 ttl=243 time=69.865 ms

-- www.php.net pingstatistics --

5 packets transmitted.5 packets received. 0% packet loss

round-trip min/avg/max/stddev- 55.339/63.662/70.779/6.783 ms

Обратныеапострофы

Существует идругой способ выполнения системных команд,не требующий вызова функций, - выполняемаякоманда заключается в обратные апострофы (``), а результаты ее работы отображаются вбраузере. Пример:

$output = `ls`;

print "<pre>$output</pre>";

Этотфрагмент выводит в браузер содержимоекаталога, в котором находится сценарий.

Внутреннийпараметр ping -с 5 (-п 5 в системе Windows) задаетколичество опросов сервера.

Если выхотите просто вернуть неформатированныерезультаты выполнения команды,воспользуйтесь функцией passthru( ), описаннойниже.

passthru( )

Функцияpassthru( ) работает почти так же, как ехес( ), заодним исключением - она автоматическивыводит результаты выполнения команды.Синтаксис функции passthru( ):

void passthru(stringкоманда [, int возврат])

Если привызове passthru( ) передается необязательныйпараметр возврат, этой переменнойприсваивается код возврата выполненнойкоманды.

escapeshellcmd( )

Функцияescapeshellcmd( ) экранирует все потенциальноопасные символы, которые могут быть введеныпользователем (например, на форме HTML), длявыполнения команд exec( ), passthru( ), system( ) илирореn( ). Синтаксис:

string escapeshellcmd(string команда)

Кпользовательскому вводу всегда следуетотноситься с определенной долейосторожности, но даже в этом случаепользователи могут вводить команды,которые будут исполняться функциямизапуска системных команд. Рассмотримследующий фрагмент:

$user_input = `rm -rf*`; // Удалить родительский каталог и все егоподкаталоги

ехес($user_input); // Выполнить $user_input!!!

Если непредпринять никаких мер предосторожности,такая команда приведет к катастрофе.Впрочем, можно воспользоваться функцийescapeshellcmd( ) для экранированияпользовательского ввода:

$user_input = `rm - rf*`; // Удалить родительский каталог и все егоподкаталоги

ехес( escapeshellcmd($user_input)); //Экранировать опасные символы

Функцияescapeshellcmd( ) экранирует символ *, предотвращаякатастрофические последствия выполнениякоманды.

Безопасностьявляется одним из важнейших аспектовпрограммирования в среде Web, поэтому япосвятил целую главу этой теме и ееотношению к программированию РНР. Задополнительной информацией обращайтесь кглаве 16.

Работа сфайловой системой

В РНРсуществуют функции для просмотра ивыполнения различных операций с файлами насервере. Информация об атрибутах серверныхфайлов (местонахождение, владелец ипривилегии) часто бывает полезной.

basename( )

Функцияbasename( ) выделяет имя файла из переданногополного имени. Синтаксис функции basename( ):

string basename(string полное_имя)

Выделениебазового имени файла из полного именипроисходит следующим образом:

$path = "/usr/local/phppower/htdocs/index.php";$file = basename($path); // $file = "index.php"

Фактическиэта функция удаляет из полного имени путь иоставляет только имя файла.

getlastmod( )

Функцияgetlastmod( ) возвращает дату и время последнеймодификации страницы, из которойвызывается функция. Синтаксис функцииgetlastmod( ):

int getlastmod(void)

Возвращаемоезначение соответствует формату даты/времениUNIX, и для его форматирования можновоспользоваться функцией date( ). Следующийфрагмент выводит дату последнеймодификации страницы:

echo "Lastmodified: ".date( "H:i:s a". getlastmod( ) );

stat( )

Функция stat( )возвращает индексируемый массив сподробной информацией о файле с заданнымименем:

array stat(stringимя_файла)

В элементахмассива возвращается следующая информация:

0 Устройство

1 Индексныйузел (inode)

2 Режимзащиты индексного узла

3 Количествоссылок

4Идентификатор пользователя владельца

5Идентификатор группы владельца

6 Типустройства индексного узла

7 Размер вбайтах

8 Времяпоследнего обращения

9 Времяпоследней модификации

10 Времяпоследнего изменения

11 Размерблока при вводе/выводе в файловой системе

12 Количествовыделенных блоков

Такимобразом, если вы хотите узнать времяпоследнего обращения к файлу, обратитесь кэлементу 8 возвращаемого массива.Рассмотрим пример:

$file - "datafile.txt";

list($dev, $inode, $inodep,$nlink, $uid, $gid, $inodev, $size, $atime, $mtime, $ctime,

$bsize) = stat($file);

print "$file is$size bytes. <br>";

print "Last accesstime: $atime <br>";

print "Lastmodification time: $mtime <br>";

Результат:

popen.php is 289 bytes.

Last access time:August 15 2000 12:00:00

Last modification time:August 15 2000 10:07:18

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

Отображениеи изменение характеристик файлов

У каждогофайла в системах семейства UNIX есть триважные характеристики:

  • принадлежностьгруппе;
  • владелец;
  • разрешения (permissions).

Все этихарактеристики можно изменить при помощисоответствующих функций РНР. Функции,описанные в этом разделе, не работают всистемах семейства Windows.

Еслиу вас нет опыта работы в операционныхсистемах UNIX, информацию о характеристикахфайловой системы UNIX можно получить поадресу http://sunsite.auc.dk/linux-newbie/FAQ2.htm. Темыпринадлежности группе, владения иразрешений рассматриваются в разделе 3.2.6.

chgrp( )

Функция chgrp( )пытается сменить группу, которойпринадлежит заданный файл. Синтаксисфункции chgrp( ):

int chgrp(string имя_файла,mixed группа)

filegroup( )

Функцияfilegroup( ) возвращает идентификатор группывладельца файла с заданным именем или FALSE вслучае ошибки. Синтаксис функции filegroup( ):

int filegroup (stringимя_файла)

chmod( )

Функция chmod( )изменяет разрешения файла с заданнымименем. Синтаксис функции chmod():

int chmod(string имя_файла,int разрешения)

Разрешениязадаются в восьмеричной системе. Спецификазадания параметра функции chmod ( )продемонстрирована в следующем примере:

chmod("data_file.txt",g+r); // He работает

chmod("data_file.txt",766); // Не работает

chmod("data_file.txt",0766); // Работает

fileperms( )

Функцияfileperms( ) возвращает разрешения файла сзаданным именем или FALSE в случае ошибки.Синтаксис функции fileperms( ):

int fileperms (stringимя_файла)

chown( )

Функцияchown( ) пытается сменить владельца файла.Право изменения владельца файлапредоставляется только привилегированномупользователю. Синтаксис функции chown( ):

int chown (string имя_файла,mixed пользователь)

fileowner( )

Функцияfileowner( ) возвращает идентификаторпользователя для владельца файла сзаданным именем. Синтаксис функции fileowner( ):

int fileowner (stringимя_файла)

Копированиеи переименование файлов

К числудругих полезных системных функций, которыемогут выполняться в сценариях РНР,относятся копирование и переименованиефайлов на сервере. Эти операции выполняютсядвумя функциями: сору( ) и rename( ).

сору( )

Скопироватьфайл в сценарии РНР ничуть не сложнее, чемпри помощи команды UNIX ср. Задача решаетсяфункцией РНР сору( ). Синтаксис функции сору( ):

int copy(string источник,string приемник)

Функция сору() пытается скопировать файл источник в файлприемник; в случае успеха возвращается TRUE, апри неудаче - FALSE. Если файл приемник несуществует, функция сору( ) создает его.Следующий пример показывает, как создатьрезервную копию файла при помощи функциисору( ):

$data_file = "datal.txt";

copy($data_file.$data_file'.bak') or die("Could not copy $data_file");

rename ( )

Функцияrename( ) переименовывает файл. В случае успехавозвращается TRUE, a при неудаче - FALSE.Синтаксис функции rename( ):

bool rename (string старое_имя,string новое_имя)

Примерпереименования файла функцией rename( ):

$data_file = "datal.txt";

rename($data file,$datafile'.old') or die ("Could not rename $data file");

Удалениефайлов

unlink( )

Функция unlink() удаляет файл с заданным именем. Синтаксис:

int unlink(string файл)

Если выработаете с РНР в системе Windows, прииспользовании этой функции иногдавозникают проблемы. В этом случае можновоспользоваться описанной выше функциейsystem( ) и удалить файл командой DOS del:

system ("delfilename.txt");

Работа скаталогами

Функции РНРпозволяют просматривать содержимоекаталогов и перемещаться по ним. В листинге7.8 изображена типичная структура каталоговв системе UNIX.

Листинг7.8. Типичнаяструктура каталогов

drwxr-xr-x 4 root wheel512 Aug 13 13:51 book/

drwxr-xr-x 4 root wheel512 Aug 13 13:51 code/

-rw-r--r-- 1 root wheel115 Aug 4 09:53 index.html

drwxr-xr-x 7 root wheel1024 Jun 29 13:03 manual/

-rw-r--r-- 1 root wheel19 Aug 12 12:15 test.php

dirname( )

Функцияdirname( ) дополняет basename( ) - она извлекает путьиз полного имени файла. Синтаксис функцииdirname( ):

string dirname (stringпуть)

Примериспользования dirname( ) для извлечения пути изполного имени:

$path = "/usr/locla/phppower/htdocs/index.php";

$file = dirname($path);// $file = "usr/local/phppower/htdocs"

Функция dirname() иногда используется в сочетании спеременной $SCRIPT_FILENAME для получения полногопути к сценарию, из которого выполняетсякоманда:

$dir - dirname($SCRIPT_FILENAME);

is_dir( )

Функция is_dir() проверяет, является ли файл с заданнымименем каталогом:

bool is_dir(string имя_файла)

В следующемпримере используется структура каталоговиз листинга 7.8:

$isdir = is_dir("index.html");// Возвращает FALSE

$isdir = is_dir("book"); //Возвращает TRUE

mkdir()

Функцияmkdir( ) делает то же, что и одноименная командаUNIX, - она создает новый каталог. Синтаксисфункции mkdir( ):

int mkdir (string путь,int режим)

Параметрпуть определяет путь для создания новогокаталога. Не забудьте завершить параметрименем нового каталога! Параметр режимопределяет разрешения, назначаемыесозданному каталогу.

opendir( )

Подобно томукак функция fopen( ) открывает манипулятор дляработы с заданным файлом, функция opendir( )открывает манипулятор для работы скаталогом. Синтаксисфункции opendir( ):

int opendir (string путь)

closedir( )

Функцияclosedir( ) закрывает манипулятор каталога,переданный в качестве параметра. Синтаксисфункции closedir( ):

void closedir(int манипулятор_каталога)

readdir( )

Функция readdir() возвращает очередной элемент заданногокаталога. Синтаксис:

string readdir(intманипулятор_каталога)

С помощьюэтой функции можно легко вывести списоквсех файлов и подкаталогов, находящихся втекущем каталоге:

$dh = opendir(' . );

while ($file = readdir($dh)):

print "$file <br>";endwhile;

closedir($dh);

chdir( )

Функцияchdir( ) работает так же, как команда UNIX cd, - онаосуществляет переход в каталог, заданныйпараметром. Синтаксис функции chdir( ):

int chdir (string каталог)

В следующемпримере мы переходим в подкаталог book/ ивыводим его содержимое:

$newdir = "book";

chdir($newdir) or die("Couldnot change to directory ($newdir)"); $dh = opendir(' . ');

print "Files:";

while ($file = readdir($dh));

print "$file <br>";

endwhile;

closedir($dh);

rewinddir( )

Функцияrewlnddir( ) переводит указатель текущей позициив начало каталога, открытого функцией opendir(). Синтаксис функции rewinddir( ):

void rewinddir (int нанипулятор_каталога)

Проект 1:простой счетчик обращений

Сценарий,представленный в этом разделе,подсчитывает количество обращений кстранице, в которой он находится. Прежде чемпереходить к программному коду в листинге7.9, просмотрите алгоритм, написанный напсевдокоде:

  1. Присвоитьпеременной $access имя файла, в котором будетхраниться значение счетчика.
  2. Использовать функцию filе( ) для чтениясодержимого $access в массив $visits. Префикс @перед именем функции подавляет возможныеошибки (например, отсутствие файла сзаданным именем).
  3. Присвоитьпеременной $current_visitors значение первого (иединственного) элемента массива $visits.
  4. Увеличитьзначение $current_visitors на 1.
  5. Открытьфайл $access для записи и установить указательтекущей позиции в начало файла.
  6. Записатьзначение $current_visitors в файл $access.
  7. Закрытьманипулятор, ссылающийся на файл $access.

Листинг7.9. Простойсчетчик обращений

<?

// Сценарий:простой счетчик обращений

// Назначение:сохранение количества обращений в файле

$access = "hits.txt";// Имя файла выбирается произвольно

$visits = @file($access);// Прочитать содержимое файла в масссив

$current_visitors = $visits[0]; // Извлечь первый (иединственный) элемент

++$current_visitors; //Увеличить счетчик обращений

$fh = fopen($access. "w");// Открыть файл hits.txt и установить

// указательтекущей позиции в начало файла

@fwrite($fh,$current_visitors);// Записать новое значениесчетчика

// в файл "hits.txt"

fclose($fh);  // Закрытьманипулятор файла "hits.txt"

?>

Проект 2:построение карты сайта

Сценарий,приведенный в листинге 7.10, строит картусайта - иерархическое изображение всехпапок и файлов на сервере, начиная сзаданного каталога. При вычисленииотступов элементов, из которых состоиткарта сайта, используются функции,определенные в этой и предыдущих главах.Прежде чем переходить к программе,просмотрите алгоритм, написанный напсевдокоде:

  1. Объявитьслужебные переменные для храненияродительского каталога, имени графическогофайла с изображением папки, названиястраницы и флага серверной ОС (Windows илидругая система).
  2. Объявитьфункцию display_directory( ), которая читаетсодержимое каталога и форматирует его длявывода в браузере.
  3. Построитьпуть к каталогу объединением имени,передаваемого в переменной $dir1, с$dir.
  4. Открытькаталог и прочитать его содержимое.Отформатировать имена каталога и файлов ивывести их в браузере.
  5. Еслитекущий файл является каталогом,рекурсивно вызвать функцию display_di rectory( ) ипередать ей имя нового каталога для вывода.Вычислить отступ, используемый приформатировании вывода.

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

Листинг7.10. Программаsitemap.php

// Файл:sitemap.php

// Назначение:построение карты сайта

// Каталог, скоторого начинается построение карты

$beg_path = "C:\ProgramFilesVApache Group\Apache\htdocs\phprecipes";

// Файл сграфическим изображением папки.

// Путьдолжен задаваться Относительно* корневогокаталога сервера Apache

$folder_location ="C:\My Documents\PHP for Programmers\FINAL CHPS\graphics\folder.gif";

// Текст взаголовке окна $page_name = "PHPRecipes SiteMap";

// В какойсистеме будет использоваться сценарий - Linuxили Windows?

// (0 - Windows; 1 - Linux)

$usingjinux = 0;

// Функция:display_directory

// Назначение:чтение содержимого каталога, определяемогопараметром

// $dir1, споследующим форматированием иерархиикаталогов и файлов.

// Функцияможет вызываться рекурсивно.

functiondisplay_directory ($dir1, $folder_location, $using_linux, $init_depth) {

// Обновитьпуть

$dir.= $dir1;

Sdh = opendir($dir);

while($file = readdir($dh)):

// Элементыкаталогов "." и ".." не выводятся.

if ( ($file !=".") && ($file != "..") ) :

if ($using_linux == 0 ):

$depth = explode("\\",$dir): else :

$depth = explode("/",$dir); endif ; $curtent_depth = sizeof( $depth);

// Построитьпуть по правилам используемой операционнойсистемы. if ($using_linux == 0) :

$tab_depth =$current_deptn - $init_depth;

$file = $dir. "\\",$file; else :

$file = $dir."/",$file; endif;

// Переменная$file содержит каталог? if ( is dir($file) ) :

$х = 0;

// Вычислитьотступ

while ( $х < ($tab_depth* 2) ) :

print "&nbsp;";

$х++; endwhile;

print "<img src=\"$folder_location\"alt=\"[dir]\">

".basename($file)."<br>";

//Увеличить счетчик &nbsp;

// Рекурсивныйвызов функции display_directory()

display_directory($file,$folder_location, $using_linux, $init_depth);

// He каталог

else :

// Построитьпуть по правилам используемой

//операционной системы.

if ($using_linux == 0) :

$tab_depth = ($current_depth- $init_depth) - 2; $x = 0;

// Вычислитьотступ

while ( $x < (($tab_depth* 2) + 5) ) :

print "&nbsp;";

$x++;

endwhile:

print "<ahref =\ "" .$dir."\\".basename($file)."\">".basename($file)."</a><br>";

else :

print "<a href= \"".$dir."/".basename($file)."\">".basename($file)."</a><br>";

endif:

endif; // Is_dir(file)endif: // If ! "." or ".."

endwhile;

// Закрытькаталог closedir($dh);

<html >

<head>

<title> <?print "$page_name"; ?> </title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#000000" vlink="#000000"alink="#000000">

<?

// Вычислитьначальный отступ

if ($using_linux == 0):

$depth = explode("\\",$beg_path);

else :

$depth = explode("/",$beg_path);

endif:

$init_depth = sizeof($depth);

display_directory ($beg_path,$folder_location, $using_linux, $init_depth);

?>

</body>

</html>

На рис. 7.1изображен результат выполнения сценариядля каталога с несколькими главами этойкниги.

 

Рис. 7.1. Выводструктуры каталога на сервере сиспользованием сценария sitemap.php

Итоги

В этой главебыли представлены многие средства РНР,предназначенные для работы с файлами. Вчастности, мы рассмотрели следующиевопросы:

  • проверкусуществования файлов;
  • открытие изакрытие файлов и потоков ввода/вывода;
  • запись вфайл и чтение из него;
  • перенаправлениефайла в выходной поток;
  • запусквнешних программ;
  • операции сфайловой системой.

Материалэтой главы подготовил почву для следующейглавы, <Строки и регулярные выражения>,поскольку при разработке web-приложенийобработка строк и операции ввода/выводаочень тесно связаны.