Php: список файлов и директорий

Введение

3–2

<!DOCTYPE html PUBLIC "-//W3C//DTD/XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml11-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>A Web Page</title>
</head>
<body>
<form action="process.php" method="post">
First Name: <input type="text" name="FName"/>
Last Name: <input type="text" name="LName"/>
City: <input type="text" name="City"/>
State: <input type="text" name="State"/>
Message: <textarea name="Message" cols="30" rows="5"></textarea>
<input type="submit" name="submit" value="Submit Data"/>
</form>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD/XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml11-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>A Web Page</title>
</head>
<body>
<form action="form_process.php" method="post">
First Name: <input type="text" name="FName"/>
Last Name: <input type="text" name="LName"/>
City: <input type="text" name="City"/>
State: <input type="text" name="State"/>
Message: <textarea name="Message" cols="30" rows="5"></textarea>
<input type="submit" name="submit" value="Submit Data"/>
</form>
</body>
</html>

Чтение и запись

Для чтения и записи существуют процедуры с понятными именами Read() и Write(). Процедуры необычые: у них неограниченное число параметров. У обеих первым параметров передаётся указатель на файл, а дальше — список переменных (или значений), с которыми нужно выполнить данную операцию. Команда Read() читает одну запись из файла и заносит её в переменную, которая указана вторым параметром. При этом указатель сдвигается на одну позицию. Если указать несколько переменных — в них будут считаны значения по порядку. Функция автоматически распознаёт разделители значений — пробелы, что позволяет с лёгкостью считывать несколько значений из файла. Запись работает аналогично: все переданные значения последовательно записываются в файл.

Помните, что пока Вы не закрыли файл, внесённые изменения в нём не сохраняются!

Пример 2. Запись в файл.

var F: TextFile; a,b: Byte;
 
AssignFile(F,'new.txt');

Rewrite(F);
a:=2;
b:=10;
Write(F,'1',a,'3 ',b);

CloseFile(F);

В данном примере показано использование Write(). В результате в файле будет строка «123 10». Были записаны как явно заданные строки, так и значения переменных.

Пример 3. Считывание из файла двух чисел.

var F: TextFile; a,b: Byte;

 
AssignFile(F,'new.txt');
Reset(F);
Read(F,a,b);

CloseFile(F);
 
ShowMessage(IntToStr(a)+' ; '+IntToStr(b));

В данном примере файл открывается для чтения (Reset) и из него считываются записанные там значения в переменные a и b. На экран будет выведено сообщение «123 ; 10».

Процедуры Read() и Write() не проверяют типов данных, которые используются при работе с файлом. Так что можно напрямую записывать числа, не преобразуя их в строки, и обратно из строк в числа при чтении.

Итак, записывать и читать данные научились. Но хватит ли этого для решения любых задач? Нет.

Гораздо чаще требуется работать с файлами построчно, т.е. считывать и записывать целые строки. Реакция функций на пробелы-разделители будет только вставлять палки в колёса. На помощь приходят функции ReadLn() и WriteLn(). Ln — сокращение от line (строка). ReadLn() читает целую строку из файла, а WriteLn() записывает данные и вставляет после них признаки конца текущей строки и начала новой. В остальном работа этих функций точно такая же.

Когда выполняется чтение файла, указазатель («курсор») перемещается автоматически. Понятно, что в какой-то момент мы придём к концу файла и дальше читать уже будет нечего. Чтобы отследить это состояние, используется функция EOF() — сокращение от end of file (конец файла). Передаём указатель на файл и узнаём, дошли ли до конца. Что может быть проще? Таким образом, чтение файла легко записывается в цикл.

Пример 4. Считывание всего файла в ListBox.

var F: TextFile; S: String;

 
ListBox1.Clear;
AssignFile(F,'new.txt');
Reset(F);
while not EOF(F) do

begin
  ReadLn(F,S);
  ListBox1.Items.Add(S)
end;

CloseFile(F);

Разберём пример построчно:

  • Очищаем ListBox.
  • Связываемся с файлом new.txt.
  • Открываем файл для чтения (указатель в начале файла).
  • До тех пор, пока не дошли до конца файла…
  • … читаем очередную строку в переменную S…
  • и добавляем эту строку в ListBox.
  • Закрываем файл.

Механизм простой, и, надеюсь понятный.

Пример 5. Сохранение всех строк из поля Memo в текстовый файл.

var F: TextFile; I: Integer;
 
AssignFile(F,'test.txt');
Rewrite(F);

for I :=  to Memo1.Lines.Count-1 do
  WriteLn(F,Memo1.LinesI);

CloseFile(F);
  • Установили связь с файлом.
  • Перезаписали файл.
  • Проходим по всем строкам Memo1…
  • … и переписываем каждую строку в файл.
  • Закрываем файл.

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

ListBox1.Items.LoadFromFile('new.txt');
Memo1.Lines.SaveToFile('test.txt');

О том, что все так любят делать…

Догадались, о чём пойдёт речь? Да-да, именно об удалении. Сломать проще, чем построить. Однако удалять ненужное — благое дело. С удалением всё не так просто, как с проверкой существования. Когда Вы пытаетесь удалить файл, какая-нибудь программа может его использовать. Естественно, файловая система удалить его не позволит.Чтобы удалить файл, следует воспользоваться функцией DeleteFile(). Параметр — путь к файлу. Функция возвращает True, если файл успешно удалился, и False, если сделать этого не получилось.

if DeleteFile('text.doc') then
  ShowMessage('Файл удален.')

else
  ShowMessage('Не удалось удалить файл.');

Для удаления папок используется функция RemoveDir():

if RemoveDir('Data') then

  ShowMessage('Папка удалена.')
else
  ShowMessage('Не удалось удалить папку.');

Есть и альтернатива — процедура RmDir(), однако об успешности удаления она не сообщает.

Как получить в PHP список файлов в папке

Можно использовать PHP scandir(), чтобы получить список всех файлов, которые содержит папка.

Пример:

<?php
        // Определение функции для вывода файлов в каталог 
       function outputFiles($path){
  	    // Проверка на существование каталога 
          if(file_exists($path) && is_dir($path)){
              // Проверка файлов в каталоге 
  	        $result = scandir($path);
  	   
              // Отфильтровать данный (.) и предыдущего уровня (..) каталоги 
              $files = array_diff($result, array('.', '..'));
              
  	        if(count($files) > 0){
  	            // Обход возвращенного массива
  	            foreach($files as $file){
                      if(is_file("$path/$file")){
  	                    // Отображение имени файла 
  	                    echo $file . "<br>";
                      } else if(is_dir("$path/$file")){
                          // Рекурсивно вызываем функцию, если каталоги найдены 
  	                    outputFiles("$path/$file");
  	                }
  	            }
  	        } else{
                  echo "ERROR: No files found in the directory.";
  	        }
  	    } else {
              echo "ERROR: The directory does not exist.";
  	    }
       }
  	 
        // Название имени файла 
       outputFiles("mydir");
        ?>

Есть ли, с чем работать?

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

Проверка существования файла выполняется функцией FileExists() — «файл существует?». Возвращаемое значение — логическое (Boolean).

if FileExists('new.txt') then
  ShowMessage('Файл существует.')
else

  ShowMessage('Файл отсутствует.');

Путь к файлу может быть как абсолютным (полный путь), так и относительным (от рабочего каталога).

Как видите, всё элементарно. А как узнать, есть ли папка? Да всё то же самое, только вместо File — Directory: DirectoryExists():

if DirectoryExists('Data') then
  ShowMessage('Папка существует.')
else

  ShowMessage('Папки нет.');

new.txtData

Абсолютный путь в URL

Абсолютный путь в URL означает путь от корня сайта. Корень сайта — это папка, которая содержит публичную часть сайта, т.е. доступную извне.

По-умолчанию корень сайта — это сама папка с сайтом, например site.ru, но зачастую её меняют на site.ru/public, чтобы часть скриптов нельзя было запустить по прямой ссылке в браузере.

  • http://test.ru/article.php — полный путь с протоколом и доменом
  • //test.ru/article.php — полный путь без протокола (берётся из текущей страницы). Содержит два слеша в начале.
  • /article.php — полный путь без протокола и домена (берутся из текущей страницы). Содержит слеш в начале.

Второй и третий варианты удобны тем, что при миграции с http на https и обратно все ссылки автоматически сменят протокол, не нужно будет бегать по всему сайту и менять вручную.

Лично я практически всегда использую третий вариант, кроме случаев, когда нужно указать ссылку на другой поддомен (blog.site.ru, shop.site.ru и т.д.).

О том, как создавать папки

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

Начнём с того, как создавать папки. Здесь всё достаточно просто. Создать папку позволяет функция CreateDir() и процедура MkDir(). Аналогично удалению, первая может сказать о том, получилось ли создать, а вторая лишь молча попробует сделать своё дело.

CreateDir('Documents');

Есть и более интересная модификация — функция ForceDirectories(). Она позволяет создать сразу целую цепочку вложенных друг в друга папок. Например, мы хотим создать папку Files, в ней Documents, а в последней — Срочное. Вариант с использованием MkDir():

MkDir('Files');

MkDir('Files\Documents');
MkDir('Files\Documents\Срочное');

Неудобно, согласитесь? И это только 3 папки. А бывают случаи, когда нужны цепочки и длиннее… Функция ForceDirectories() автоматически создаёт всё недостающее по указанному пути. Одна особенность — функция требует на вход полного (абсолютного) пути. Для нашего примера:

ForceDirectories(GetCurrentDir()+'\Files\Documents\Срочное');

C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Files\Documents\Срочное

Чем отличаются пути в PHP и URL

Когда мы смотрим любимый фильм или сериал, мы видим только готовый продукт.

А за кадром существует совсем другой, невидимый для нас мир: стилисты и гримёры, искусственные декорации, наложение спецэффектов и многое другое.

Процесс съёмок музыкального клипа

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

Если ты видишь на каком-нибудь сайте страницу с URL /category/monitors — это совсем не значит, что на сайте есть скрипт /category/monitors/index.php.

Вполне вероятно, что и такой папки там тоже нет, а все URL адреса обрабатываются одним единственным PHP файлом.

И даже если в URL присутствует расширение файла, например /about.html — это тоже не говорит о существовании файла about.html. Может он есть, а может и нет.

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

Ошибка №1: Подстановка физического пути в URL

Очень частая ошибка новичков — пытаться подставить в URL адрес ссылку на физический файл, вроде такого:

Это неправильно. Браузер не может видеть реальную файловую структуру сервера. Он не видит никаких дисков D, он видит только URL адреса.

Правильная ссылка выглядит так (разницу объясню чуть позже):

Ошибка №2: Подключение скриптов по URL

Иногда новички пытаются подключить физический файл по его URL:

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

Как правильно:

Домашнее задание

Для усвоения пройденного предлагаю создать следующую программу.

На форме два поля для ввода текста. В первое вводится путь к некоторой папке, а во второе — текстовая строка, содержащая символ «*» (звёздочка). Дополнительно (с помощью каких-либо компонентов) вводятся два числа. Требуется в указанной папке создать текстовые файлы с именами из второго поля, заменив звёздочку на числа из заданного диапазона. При этом, если такой файл уже был на диске, нужно дописать в него текущее время, а если его не было — то и дату, и время.

Подсказка: текущее время в виде строки можно получить как TimeToStr(Now), а дату — DateToStr(Now).

Примерный вид окна программы приведён на рисунке справа. Для указанных исходных данных на диске C:\ будут созданы файлы Test1.txt, Test2.txt, …, Test5.txt.

Ссылки по теме

Вспомним, о чём, собственно, речь…

Для обычного пользователя, который не занимается программированием, знать о файлах и папках много не нужно. Достаточно иметь базовые представления, что это такое, как это используется, и какие возможны операции. Однако при программировании необходимо понимание того, что находится «внутри» и как всё это работает.Итак, файл. Существуют сотни определений этого слова, но все они крутятся вокруг одно и того же. Файл (file) — это совокупность байтов, хранящаяся во внешней памяти и имеющая своё имя. Каждый файл мы можем найти именно по его имени. Каталог (папка, директория — folder, directory) — это своеобразный контейнер для файлов и для других папок. Каждая папка считается абсолютно «резиновой», т.е. мы можем класть в неё файлы до тех пор, пока есть место на диске: объём папки не ограничен. Эти два ключевых понятия неразрывно связаны между собой. В рамках одной папки имена файлов уникальны, т.е. не может быть двух файлов с одним именем. Следует отметить, что регистр, в котором написаны имена файлов и папок, играет свою роль. В операционной системе Windows заглавные и строчные буквы не различаются и к файлу file.txt можно запросто обратиться FILE.TXT и даже fIlE.TxT — система это прекрасно поймёт и проведёт Вас к одному и тому же файлу. Однако в некоторых других операционных системах этот принцип не работает — FILE.TXT и file.txt — два совершенно разных файла. Говорить о том, какой вариант лучше, можно долго — у каждого варианта есть свои преимущества и свои недостатки. Где ещё мы думаем или, наоборот, не задумываемся о регистре? Язык Pascal регистро-независимый: можно писать в любом регистре — как больше нравится или как удобнее. Код, написанный в любом регистре, интерпретируется совершенно одинаково. Речь не идёт, конечно, о строках и символах: при их обработке регистр, естественно, важен.Что ещё мы должны знать? Каждый файл имеет расширение. Как правило, это 3 символа, хотя современные файловые и операционные системы позволяют делать его и большей длины. У файлов и папок есть атрибуты — некоторые свойства. Кроме того, файловая система хранит некоторую дополнительную информацию о файлах и папках — дата и время создания, открытия, изменения файла, автора и пр.Ну что же, вроде бы основные моменты вспомнили. Теперь начнём постепенно разбираться, как же со всем этим хозяйством можно работать в Delphi.

Относительный путь в PHP

У относительных путей в PHP есть один подвох — они могут строиться относительно не той папки, от которой мы ожидаем.

Дело в том, что когда мы подключаем скрипт по относительному пути require(‘config.php’);, PHP будет искать его по следующему алгоритму:

  • Сначала PHP попытается найти этот файл в папках, указанных в директиве include_path. Посмотреть, что указано в этой директиве конкретно у вас можно с помощью var_dump(get_include_path());, папки разделяются символом ;

    Если мы укажем путь к скрипту в таком виде: require(‘./config.php’);, то этот шаг будет пропущен.

  • Затем PHP попытается найти файл в папке, в которой находится подключающий скрипт (в нашем случае index.php).
  • Далее PHP попытается найти файл в папке текущего рабочего каталога.

    Например, если мы в index.php подключили файл scripts/script.php, а в этом самом script.php уже пытаемся подключить файл по относительному пути, тогда поиск файла произойдёт и в папке scripts тоже.

Два последних пункта — главная проблема относительных путей. Мы не можем быть уверены, что будет подключен именно тот файл, который нам нужен.

Именно по этой причине я призываю тебя отказаться от использования относительных путей в PHP.

Кому-то из практикующих разработчиков эта фраза может не понравиться, но я считаю это единственным разумным решением.

Тем более нет ничего сложного в добавлении константы __DIR__ перед именем скрипта, что автоматически сделает путь абсолютным.

Абсолютный путь в PHP

Абсолютный путь — это полный путь к папке или файлу. Вот пара примеров для разных операционных систем:

  • D:\OpenServer\domains\test.ru\index.php — для OpenServer на Windows
  • /var/www/html/test.ru/index.php — для Ubuntu

Как видите, это полный путь от корня диска до конкретного файла или папки. Начинается со слеша или буквы диска (Windows).

Получить абсолютный путь скрипта можно с помощью магической константы __FILE__:

Для получения абсолютного пути к папке, в которой находится скрипт, есть магическая константа __DIR__:

Как этим пользоваться. Допустим, у нас в корне сайта лежат файлы index.php и config.php и мы хотим подключить второй в первый.

Если мы хотим подключить config.php по его абсолютному пути, есть два способа сделать это:

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

Список файлов определенного типа

При работе с папками и файлами может потребоваться найти файлы определенных типов. Например, только файлы .text или .png. Для этого предназначена функция glob(). которая осуществляет поиск файлов по заданному шаблону.

В приведенном ниже примере PHP найдет в папке все файлы с расширением .text. Данный пример не будет искать подкаталоги, как и PHP scandir().

Пример:

<?php
        /* Поиск каталога и цикл по возвращенному массиву, содержащему обозначенные файлы */
       foreach(glob("documents/*.txt") as $file){
  	    echo basename($file) . " (size: " . filesize($file) . " bytes)" . "<br>";
       }
        ?>

Функция glob() также используется для нахождения всех файлов в каталоге или подкаталоге.

Пример:

<?php
        // Определение функции для вывода файлов из каталога
       function outputFiles($path){
  	    // Проверка существования каталога
          if(file_exists($path) && is_dir($path)){
              // Поиск файлов в каталоге 
  	        $files = glob($path ."/*");
  	        if(count($files) > 0){
  	            // Циклический обход возвращённого массива
  	            foreach($files as $file){
  	                if(is_file("$file")){
  	                    // Отображаем только имя файла
  	                    echo basename($file) . "<br>";
                      } else if(is_dir("$file")){
                          // Рекурсивно вызываем функцию, если каталоги найдены 
  	                    outputFiles("$file");
  	                }
  	            }
  	        } else{
                  echo "ERROR: No such file found in the directory.";
  	        }
  	    } else {
              echo "ERROR: The directory does not exist.";
  	    }
       }
  	 
        // Вызвать функцию 
       outputFiles("mydir");
        ?>

Пожалуйста, опубликуйте свои мнения по текущей теме материала. За комментарии, подписки, лайки, дизлайки, отклики низкий вам поклон!

Пожалуйста, оставляйте свои мнения по текущей теме статьи. За комментарии, лайки, подписки, отклики, дизлайки низкий вам поклон!

КККонстантин Кондрусинавтор статьи «PHP Parsing Directories»

Пример.

<!DOCTYPE html PUBLIC "-//W3C//DTD/XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml11-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>A Web Page</title>
</head>
<body>
<form action="form_process.php" method="post">
First Name: <input type="text" name="FName"/>
Last Name: <input type="text" name="LName"/>
City: <input type="text" name="City"/>
State: <input type="text" name="State"/>
Message: <textarea name="Message" cols="30" rows="5"></textarea>
<input type="submit" name="submit" value="Submit Data"/>
</form>
</body>
</html>

Проверка формы

3–6

  1. Ввод данных формы и щелчок на кнопке отправки.
  2. Проверка ввода с помощью функций PHP.
  3. Обработка (запись в файл, генерация автоматического сообщения e-mail или воспроизведение ввода на экране) данных с помощью PHP.
<!DOCTYPE html PUBLIC "-//W3C//DTD/XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml11-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>A Web Page</title>
</head>
<body>
<form method="post" action="http://...form_validate.php"/>
Enter Name: <input type="text" name="name"/>
Enter user name: <input type="text" name="uname"/>
Enter Password (must contain at least 4 characters): <input type="password"
name="pass"/>
<input type="submit" name="submitB" value="Submit"/>
</form>
</body>
</html>

Создание папки или структуры папок

Создать папку можно с помощью функции mkdir() (make directory):

Вторым параметром указываются права доступа к файлу в виде восьмеричного числа, по-умолчанию это 0777, что означает самые широкие права. Для Windows этот аргумент игнорируется.

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

Также мы можем создать структуру папок рекурсивно, для этого нужно третьим параметром передать true:

Но в этом случае права доступа будут заданы только для конечной папки. Для изменения прав у каждой из папок придётся указывать права вручную:

Права доступа — это отдельная объёмная тема, поэтому сейчас мы её пока рассматривать не будем.

Относительный путь в URL

Относительные пути в URL указываются без слеша в начале ссылки, например:

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

Чаще всего их использование приводит к путанице. И вот пара типичных проблем, с которыми часто сталкиваются новички.

Ошибка №1: относительные пути к стилям, скриптам и другим файлам

Представим, что мы решили подключить стили к нашему сайту:

Разработчик указывает относительный URL style.css и видит, что всё работает. По крайней мере, на главной странице.

Но при переходе по любой ссылке, например /products/15, стили перестают работать.

А причина в том, что относительный путь строится от текущего URL-адреса, а значит в нашем примере он из style.css превратился в /products/15/style.css.

Ошибка №2: Рекурсия в ссылках

При использовании относительных путей есть риск случайно создать на сайте бесконечные ссылки. Вот один из таких способов:

Для работы данного кода должна быть настроена единая точка входа.

Проблема в том, что при каждом клике по этой ссылке текущий URL будет не перезаписываться, а дополняться, в итоге через несколько кликов мы получим что-то вроде http://test.ru/articles/articles/articles/articles/about.

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: