Добро пожаловать!
Здесь вы можете найти ответ на интересующий вас вопрос в отрасли сайтостроения, познакомится ближе с web технологиями и web стандартами.

PHP и MySQL

Глава 6. Работа с файлами

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

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

Открытие файлов в файловой системе сервера производится при помощи функции fopen:

int fopen(string filename, string mode [, int use_include_path])

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

Второй аргумент mode говорит о том, для каких действий открывается файл и может принимать следующие значения:

  • r   Открыть файл только для чтения; после открытия указатель файла устанавливается в начало файла;
  • r+ Открыть файл для чтения и записи; после открытия указатель файла устанавливается в начало файла;
  • w   Создать новый пустой файл только для записи; если файл с таким именем уже есть вся информация в нем уничтожается;
  • w+ Создать новый пустой файл для чтения и записи; если файл с таким именем уже есть вся информация в нем уничтожается;
  • a   Открыть файл для дозаписи; данные будут записываться в конец файла;
  • a+ Открыть файл для дозаписи и чтения данных; данные будут записываться в конец файла;
  • b   Флаг, указывающий на работу (чтение и запись) с двоичным файлом; указывается только в Windows.

Третий необязательный аргумент use_include_path определяет должны ли искаться файлы в каталоге include_path. (Параметр include_path устанавливается в файле php.ini).

В случае удачного открытия файла, функция fopen возвращает дескриптор файла, в случае неудачи — false. Дескриптор файла представляет собой указатель на открытый файл, который используется операционной системой для поддержки операций с этим файлом. Возвращенный функцией дескриптор файла необходимо затем указывать во всех функциях, которые в дальнейшем будут работать с этим файлом.

Код, приведенный ниже, открывает файл C:/www/html/file.txt для чтения:

<?php
  $file 
fopen("C:/www/html/file.txt""r");
  if ( !
$file ) echo ( "Ошибка открытия файла" );
?>

Открытие двоичного файла, к примеру, рисунка происходит таким же образом, только с флагом b:

<?php
  $file 
fopen("C:/www/html/river.jpg""rb");
  if ( !
$file ) echo ( "Ошибка открытия файла" );
?>

6.2. Отображение файлов

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

  int fpassthru ( int file )

Аргумент file представляет собой дескриптор файла.

<?php
  $file 
fopen"C:/www/html/pavlovo.jpg""rb" );
  if( !
$file )
      echo 
"Ошибка открытия файла";
  else
      
fpassthru$file );
?>

6.3. Закрытие файлов

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

  int fclose ( int file )

Аргумент file представляет собой дескриптор файла, который необходимо закрыть.

6.4. Чтение из файлов и запись в файлы

6.4.1. Чтение из файлов

Прочитать строку из открытого файла можно с помощью функции fread:

  string fread ( int file, int length )

Эта функция возвращает строку длиной length символов из файла с дескриптором file.

Пример (чтение из файла):

<?php
  $file 
fopen"C:/www/html/file.txt""r" );
  if( !
$file )
  {
      echo 
"Ошибка открытия файла";
  }
  else
  {
      
$buff fread$file100 );
      print 
$buff;
  }
?>

Для чтения из файла можно также пользоваться функцией fgets:

   string fgets ( int file, int length )

Эта функция читает и возвращает строку длиной length-1 байт. Чтение прекращается, когда достигнута новая строка или конец файла. При достижении конца файла функция возвращает пустую строку.

Для чтения файла с удалением из него тегов HTML применяется функция fgetss:

   string fgetss (int file, int length [, string allowable_tags])

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

Если необходимо считать содержимое файла в массив, применяется функция file:

   array file ( string filename [, int use_include_path] )

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

<?php
  $arr 
file"file.txt" );
  if( !
$arr )
  {
      echo 
"Ошибка открытия файла";
  }
  else
  {
      for( 
$i=0$i count($arr); $i++ )
      {
          echo 
$arr[$i]."<br/>";
      }
  }
?>

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

<?php
  $arr 
=  file"file.txt" );
  if ( !
$arr )
  {
      echo 
"Ошибка открытия файла";
  }
  else
  {
      
$num_str count$arr ); 
      echo 
$num_str;
  }
?>

Заметим, что функцию file следует применять лишь для чтения небольших файлов.

Для чтения файлов с расширением *.csv применяется функция fgetcsv:

  array fgetcsv ( int file, int length, char delim )

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

Формат CSV является одним из форматов, в котором может сохранять файлы MS Excel. В следующем примере производится чтение созданного MS Excel файла file.csv.

<?
  $count 
1;
  
$file =  fopen "file.csv""r" );
  while ( 
$data fgetcsv($file1024",") ) 
  {
    
$num count $data );
    echo 
"Строка ".$count."<br/>";
    for (
$i 0$i $num$i++) 
    {
      echo 
$data[$i]."<br/>";
    }
    
$count++;
  }
  
fclose $file );
?> 

6.4.2. Запись в файлы

Запись в файлы осуществляется функциями fputs и fwrite, которые абсолютно идентичны:

  int fputs ( int file, string string [, int length ] )

  int fwrite ( int file, string string [, int length ] )

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

В этом примере в файл file.txt записывается строка "Hello, world!"

<?
  $file 
fopen "file.txt""r+" );
  
$str "Hello, world!";
  if ( !
$file )
  {
    echo( 
"Ошибка открытия файла" );
  }
  else
  {
    
fputs $file$str );
  }
  
fclose $file );
?>

6.5. Копирование, переименование и удаление файлов

Копирование файлов осуществляется функцией copy:

  int copy ( string file1, string file2 )

Функция копирует файл с именем file1 в файл с именем file2. Если файл file2 на момент копирования существовал, то он перезаписывается.

Переименование файла производится с помощью функции rename:

  int rename ( string old, string new )

Эта функция переименовывает файл с именем old в файл с именем new. Функция rename не выполняет переименования файла, если его новое имя расположено в другой файловой системе.

Удаление файла осуществляется посредством функции unlink:

  int unlink ( string filename )

6.6. Атрибуты файлов

Для получения дополнительной информации об атрибутах файла вы можете воспользоваться перечисленными ниже функциями.

Функция file_exists проверяет, существует ли файл и возвращает true, если файл существует и false в противном случае:

  bool file_exists ( string filename )

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

  int fileatime ( string filename )

Функция filemtime возвращает время последней модификации содержимого файла:

  int filemtime ( string filename )

Функция filesize возвращает размер файла в байтах:

  int filesize ( string filename )

Функция filetype возвращает тип файла:

  string filetype ( string filename )

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

  • char (специальное символьное устройство);
  • dir (каталог);
  • fifo (именованный канал);
  • link (символическая ссылка);
  • block (специальное блочное устройство);
  • file (обычный файл);
  • unknown (тип не установлен).

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

<?
  clearstatcache();
?>

6.7. Перемещение по файлам

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

Установка указателя текущей позиции в начало файла производится функцией rewind:

  int rewind ( int file )

Аргумент file является дескриптором файла.

Узнать текущее положение указателя можно при помощи функции ftell:

  int ftell ( int file )

Установить указатель в любое место файла можно, используя функцию fseek:

  int fseek ( int file, int offset [, int whence ])

Функция fseek устанавливает указатель файла на байт со смещением offset (от начала файла, от его конца или от текущей позиции, в зависимости от значения параметра whence). Аргумент file представляет собой дескриптор файла. Аргумент whence задает с какого места отсчитывается смещение offset и может принимать одно из следующих значений:

  • SEEK_SET (отсчитывает позицию начала файла);
  • SEEK_CUR (отсчитывает позицию относительно текущего положения указателя);
  • SEEK_END (отсчитывает позицию относительно конца файла).

По умолчанию аргумент whence имеет значение SEEK_SET.

Узнать, находится ли указатель в конце файла, можно с помощью функции feof:

  int feof ( int file )

Если указатель находится в конце файла, функция возвращает true, в ином случае возвращается false.

Функцию feof удобно использовать при чтении файла:

<?
  $file 
fopen "file.txt""r" );
  if (
$file)
  {
    while( !
feof($file) )
    {
      
$str fgets $file );
      echo 
$str."<br/>";
    }
    
fclose $file );
  }
  else
  {
    echo 
"Ошибка открытия файла";
  }
?>

При помощи этой функции удобно также определять количество строк в файле:

<?
  $file 
fopen "file.txt""r" );
  if ( 
$file )
  {
    
$counter 0;
    while( !
feof($file) )
    {
      
$str fgets $file );
      
$counter++;
    }
    echo 
"Количество строк: ".$counter;
    
fclose $file );
  }
  else
  {
    echo 
"Ошибка открытия файла";
  }
?>

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

Для установки текущего каталога применяется функция chdir:

  int chdir ( string directory )

Работать с этой функцией можно следующим образом:

chdir "/tmp/data" ); // переход по абсолютному пути
chdir "./js" );      // переход в подкаталог текущего каталога
chdir ".." );        // переход в родительский каталог
chdir "~/data" );    // переходим в /home/пользователь/data (для Unix)

Чтобы узнать текущий каталог можно воспользоваться функцией getcwd:

  string getcwd ( string path )

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

  int opendir ( string path)

После того, как каталог открыт, прочитать его можно функцией readdir:

  string readdir ( int dir )

Эта функция возвращает имена элементов, содержащихся в каталоге. Кроме файлов и папок в каталогах находятся также элементы "." и "..". Первый элемент указывает на текущий каталог, а второй - на родительский. Текущий каталог, кстати, можно открыть, указав его имя как ".":

$dir opendir "." );

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

  void closedir ( $dir )

Ниже приведен пример, осуществляющий чтение и вывод файлов, находящихся в текущем каталоге.

<?
  $dir 
opendir "." );
  echo 
"Files:<br/><br/>";
  while ( 
$file readdir ($dir) ) 
  {
    echo 
$file."<br/>";
  }
  
closedir $dir );
?>

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

<?
  $dir 
opendir "." );
  while ( 
$file readdir ($dir) )
  {
    if ( (
$file != ".") && ($file != "..") )
    {
      echo 
$file."<br/>";
    }
  }
  
closedir $dir );
?>

В качестве примера на рассмотренные функции, давайте создадим скрипт, удаляющий все файлы из каталога C:/temp, к которым не было доступа в течение суток. Функция удаления файлов в этом случае вызывается рекурсивно.

<?
  
function delTemporaryFiles $directory )
  {
    
$dir opendir $directory );
    while ( 
$file readdir($dir) )
    {
      if ( 
is_file $directory."/".$file ) )
      {
        
$acc_time fileatime $directory."/".$file );
        
$time =  time();
        if ( (
$time $acc_time) > 24*60*60 )
        {
          if ( 
unlink($directory."/".$file) )
          {
            echo (
"Файлы успешно удалены");
          }
        }
      }
      else if ( 
is_dir($directory."/".$file) && ($file != ".") && ($file != "..") )
      {
        
delTemporaryFiles $directory."/".$file );
      }
    }
    
closedir $dir );
  }
  
  
delTemporaryFiles "C:/temp" );
?>

Создание каталогов производится с помощью функции mkdir:

  bool mkdir ( string dirname, int mode )

Эта функция создает каталог с именем dirname и правами доступа mode. В случае неудачи возвращает false. Права доступа задаются только для каталогов UNIX, поскольку в Windows этот аргумент игнорируется. Ниже приведен пример создания каталога test в директории C:/temp.

<?
  $flag 
mkdir "C:/temp/test"0700 );
  if ( 
$flag )
    echo 
"Каталог успешно создан";
  else
    echo 
"Ошибка создания каталога";
?>

Удалить каталог можно с помощью функции rmdir:

  bool rmdir ( string dirname )

Теперь удалим только что созданный каталог test:

<?
  $flag 
rmdir "C:/temp/test" );
  if ( 
$flag )
    echo 
"Каталог успешно удален";
  else
    echo 
"Ошибка удаления каталога";
?>

Функция rmdir удаляет только пустые каталоги. Для того чтобы удалять непустые каталоги, давайте напишем функцию и удалим каталог C:/temp со всеми вложенными папками и файлами:

<?
  
function full_del_dir $directory )
  {
    
$dir opendir $directory );
    while ( 
$file readdir($dir) )
    {
      if ( 
is_file($directory."/".$file) )
      {
        
unlink $directory."/".$file );
      }
      else if ( 
is_dir($directory."/".$file) && ($file != ".") && ($file != "..") )
      {
        
full_del_dir $directory."/".$file );  
      }
    }
    
closedir $dir );
    
rmdir $directory );
    echo 
"Каталог успешно удален";
  }

  
full_del_dir "C:/temp" )
?>

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

6.9. Методы PUT и POST

Методы HTTP PUT и HTTP POST предназначены для загрузки файлов на сервер.

Протокол HTTP предоставляет три метода для работы с информацией, находящейся на Web-сервере: GET, PUT и POST. Метод GET применяется для получения Web-страниц, при этом все переменные формы передаются в URL. Поскольку на многих Web-серверах установлено ограничение на максимальную длину URL (как правило, не более 1024), не стоит применять метод GET, если требуется передача данных большего объема.

Метод PUT применяется для обновления информации на сервере, и требует, чтобы содержимое запроса HTTP PUT сохранялось на сервере. Запрос выглядит таким образом:

   PUT /path/filename.html HTTP/1.1

В этом случае Web-сервер должен сохранить содержимое этого запроса в виде /path/filename.html в пространстве имен URL Web-сервера. По умолчанию сам Web-сервер не выполняет такие запросы, а задает CGI-сценарий для их обработки. В Apache назначить сценарий для обработки PUT-запросов, можно изменив директиву Script, находящуюся в файле httpd.conf, к примеру, так:

   Script PUT /cgi-bin/put.cgi

Это означает, что обрабатывать PUT-запросы будет CGI-скрипт put.cgi.

Как правило, для загрузки файлов на сервер используют метод HTTP POST. Этот метод позволяет передавать большие объемы данных из формы и сохраняет все переменные формы в теле запроса.