Обработка ошибок — очень важная часть любого языка программирования. У Bash нет лучшего варианта, чем другие языки программирования, для обработки ошибки скрипта. Но важно, чтобы скрипт Bash был безошибочным во время выполнения скрипта из терминала. Функция обработки ошибок может быть реализована для сценария Bash несколькими способами. В этой статье показаны различные методы обработки ошибок в сценарии Bash.
Пример 1. Обработка ошибок с использованием условного оператора
Создайте файл Bash со следующим сценарием, который показывает использование условного оператора для обработки ошибок. Первый оператор «if» используется для проверки общего количества аргументов командной строки и вывода сообщения об ошибке, если значение меньше 2. Затем значения делимого и делителя берутся из аргументов командной строки. Если значение делителя равно 0, генерируется ошибка, и сообщение об ошибке печатается в файле error.txt. Вторая команда «if» используется для проверки того, является ли файл error.txt пустым или нет. Сообщение об ошибке печатается, если файл error.txt не пуст.
#!/bin/bash #Проверить значения аргументов if [ $# -lt 2 ]; then echo "Отсутствует один или несколько аргументов." exit fi #Чтение значения делимого из первого аргумента командной строки dividend=$1 #Читание значения делителя из второго аргумента командной строки divisor=$2 #Деление делимого на делитель result=`echo "scale=2; $dividend/$divisor"|bc 2>error.txt` #Читать содержимое файла ошибки content=`cat error.txt` if [ -n "$content" ]; then #Распечатать сообщение об ошибке, если файл error.txt непустой echo "Произошла ошибка, кратная нулю." else #Распечатать результат echo "$dividend/$divisor = $result"
Вывод:
Следующий вывод появляется после выполнения предыдущего скрипта без каких-либо аргументов:
andreyex@andreyex:-/Desktop/bash$ bash error1.bash One or more argument is missing. andreyex@andreyex:~/Desktop/bash$
Следующий вывод появляется после выполнения предыдущего скрипта с одним значением аргумента:
andreyex@andreyex:-/Desktop/bash$ bash error1.bash 75 One or more argument is missing. andreyex@andreyex:~/Desktop/bash$
Следующий вывод появляется после выполнения предыдущего скрипта с двумя допустимыми значениями аргумента:
andreyex@andreyex:-/Desktop/bash$ bash error1.bash 75 8 75/8 = 9.37 andreyex@andreyex:-/Desktop/bash$
Следующий вывод появляется после выполнения предыдущего скрипта с двумя значениями аргументов, где второй аргумент равен 0. Выводится сообщение об ошибке:
andreyex@andreyex:~/Desktop/bash$ bash error1.bash 75 0 Divisible by zero error occurred. andreyex@andreyex:~/Desktop/bash$
Пример 2: Обработка ошибок с использованием кода состояния выхода
Создайте файл Bash со следующим сценарием, который показывает использование обработки ошибок Bash по коду состояния выхода. Любая команда Bash принимается в качестве входного значения, и эта команда выполняется позже. Если код состояния выхода не равен нулю, печатается сообщение об ошибке. В противном случае печатается сообщение об успешном выполнении.
#!/bin/bash #Взять имя команды Linux echo -n "Введите команду: " read cmd_name #Выполнить команду $cmd_name #Проверить, действительна ли команда, if [ $? -ne 0 ]; then echo "$cmd_name - недопустимая команда." else echo "$cmd_name является корректной командой." fi fi
Вывод:
Следующий вывод появляется после выполнения предыдущего скрипта с допустимой командой. Здесь «data» принимается как команда во входном значении, которая является допустимой:
andreyex@andreyex:-/Desktop/bash$ bash error2.bash Enter a command: date Tue Dec 27 19:18:39 +06 2022 date is a valid command. andreyex@andreyex:-/Desktop/bash$
Следующий вывод появляется после выполнения предыдущего скрипта для недопустимой команды. Здесь «cmd» воспринимается как недопустимая команда во входном значении:
andreyex@andreyex:-/Desktop/bash$ bash error2.bash Enter a command: cmd error2.bash: line 7: cmd: command not found cmd is a invalid command. andreyex@andreyex: -/Desktop/bash$
Пример 3: остановить выполнение при первой ошибке
Создайте файл Bash со следующим сценарием, который показывает метод остановки выполнения при появлении первой ошибки сценария. В следующем скрипте используются две недопустимые команды. Таким образом, выдаются две ошибки. Сценарий останавливает выполнение после выполнения первой недопустимой команды с помощью команды «set -e».
#!/bin/bash #Установите параметр для завершения скрипта при первой ошибке set -e echo 'Текущие дата и время: ' #Действительная команда date echo 'Текущий рабочий каталог: ' #Неверная команда cwd echo 'имя пользователя: ' #Действительная команда whoami echo 'Список файлов и папок: ' #Неверный список list
Вывод:
Следующий вывод появляется после выполнения предыдущего скрипта. Сценарий останавливает выполнение после выполнения недопустимой команды «cwd»:
andreyex@andreyex:-/Desktop/bash$ bash error3.bash Current date and time: Tue Dec 27 19:19:38 +06 2022 Current orking Directory: error3.bash: line 9: cwd: command not found andreyex@andreyex:-/Desktop/bash$
Пример 4: остановить выполнение для неинициализированной переменной
Создайте файл Bash со следующим сценарием, который показывает метод остановки выполнения сценария для неинициализированной переменной. Значения имени пользователя и пароля берутся из значений аргументов командной строки. Если какое-либо из значений этих переменных не инициализировано, выводится сообщение об ошибке. Если обе переменные инициализированы, сценарий проверяет, являются ли имя пользователя и пароль действительными или недействительными.
#!/bin/bash #Установите параметр завершения сценария для неинициализированной переменной set -u #Установите значение первого аргумента командной строки на имя пользователя username=$1 #Проверьте правильность или недопустимость имени пользователя и пароля password=$2 #Проверьте правильность или недопустимость имени пользователя и пароля if [[ $username == 'admin' && $password == 'hidenseek' ]]; then echo "Действительный пользователь." else echo "Неверный пользователь." fi
Вывод:
Следующий вывод появляется, если сценарий выполняется без использования какого-либо значения аргумента командной строки. Скрипт останавливает выполнение после получения первой неинициализированной переменной:
andreyex@andreyex:~/Desktop/bash$ bash error4.bash error4.bash: line 7: $1: unbound variable andreyex@andreyex:~/Desktop/bash$
Следующий вывод появляется, если сценарий выполняется с одним значением аргумента командной строки. Скрипт останавливает выполнение после получения второй неинициализированной переменной:
andreyex@andreyex:-/Desktop/bash$ bash error4.bash admin error4.bash: line 9: $2: unbound variable andreyex@andreyex:-/Desktop/bash$
Следующий вывод появляется, если сценарий выполняется с двумя значениями аргумента командной строки — «admin» и «hide». Здесь имя пользователя действительно, но пароль недействителен. Итак, выводится сообщение «Invalid user»:
andreyex@andreyex:-/Desktop/bash$ bash error4.bash admin hide Invalid user. andreyex@andreyex:-/Desktop/bash$
Следующий вывод появляется, если сценарий выполняется с двумя значениями аргументов командной строки — «admin» и «hidenseek». Здесь имя пользователя и пароль действительны. Итак, выводится сообщение «Valid user»:
andreyex@andreyex:-/Desktop/bash$ bash error4.bash admin hidenseek Valid user. andreyex@andreyex:~/Desktop/bash$
Заключение
Различные способы обработки ошибок в скрипте Bash показаны в этой статье на нескольких примерах. Мы надеемся, что это поможет пользователям Bash реализовать функцию обработки ошибок в своих сценариях Bash.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Разрабатывая приложения вам придется работать с файлами, анализировать большие объемы данных, сохранять пользовательские данные, чтобы они не терялись по завершению работы программы. Также при работе с файлами важно научиться обрабатывать ошибки, чтобы они не привели к аварийному завершению программы. Для этого в Python существуют специальные объекты — исключения, которые создаются для управления ошибок.
Содержание страницы: |
---|
1. Чтение файла |
1.2. Чтение больших файлов и работа с ними |
1.3. Анализ текста из файла |
2. Запись в файл |
2.1. Запись в пустой файл |
2.2. Многострочная запись в файл |
2.3. Присоединение данных к файлу |
3. Исключения |
3.1. Блоки try-except |
3.2. Блоки try-except-else |
3.3. Блоки try-except с текстовыми файлами |
3.4. Ошибки без уведомления пользователя |
1. Чтение файла в Python
В файлах может содержаться любой объем данных, начиная от небольшого рассказа и до сохранения истории погоды за столетия. Чтение файлов особенно актуально для приложений, предназначенных для анализа данных. Приведем пример простой программы, которая открывает файл и выводит его содержимое на экран. В примере я буду использовать файл с числом «Пи» с точностью до 10 знаков после запятой. Скачать этот файл можно прямо здесь ( pi_10.txt ) или самим создать текстовый файл и сохранить под любым именем. Пример программы, которая открывает файл и выводит содержимое на экран:
with open(‘pi_10.txt’) as file_pi:
digits = file_pi.read()
print(digits)
Код начинается с ключевого слова with. При использование ключевого слова with используемый файл открывается с помощью функции open(), а закрывается автоматически после завершения блока with и вам не придется в конце вызывать функцию close(). Файлы можно открывать и закрывать явными вызовами open() и close(). Функция open() получает один аргумент — имя открываемого файла, в нашем случае ‘pi_10.txt’. Python ищет указанный файл в каталоге, где хранится файл текущей программы. Функция open() возвращает объект, представляющий файл ‘pi_10.txt’. Python сохраняет этот объект в переменной file_pi .
После появления объекта, представляющего файл ‘pi_10.txt’, используется метод read(), который читает все содержимое файла и сохраняет его в одной строке в переменной contents. В конце с помощью функции print содержимое выводится на экран. Запустив этот файл, мы получим данные, находящиеся в нашем файле ‘pi_10.txt’.
3.1415926535
В случае, если файл расположен не в одном каталоге с файлом программы, необходимо указать путь, чтобы Python искал файлы в конкретном месте. Существует два пути как прописать расположение файла:
-
Относительный путь.
Относительный путь приказывает Python искать файлы в каталоге, который задается относительно каталога, в котором находится текущий файл программы
with open(‘files/имя_файла.txt’) as file:
-
Абсолютный путь.
Местонахождение файла не зависит от того, где находится ваша программа. Абсолютные пути обычно длиннее относительных, поэтому их лучше сохранить в переменную и затем передать функции open().
file_path = ‘/Users/Desktop/files/имя_файла.txt’
with open(file_path) as file:
С абсолютными путями можно читать файлы из любого каталога вашей системы.
1.2. Чтение больших файлов на Python и работа с ними
В первом примере был файл с 10 знаками после запятой. Теперь давайте проанализируем файл с миллионом знаков числа «Пи» после запятой. Скачать число «Пи» с миллионом знаков после запятой можно отсюда( ‘pi_1000000.txt’ ). Изменять код из первого примера не придется, просто заменим файл, который должен читать Python.
Выведем на экран первые 100 знаков после запятой. Добавим в конец функцию len, чтобы узнать длину файла
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
1000002
Из выходных данных видно, что строка содержит значение «Пи» с точностью до 1 000 000 знаков после запятой. В Python нет никаких ограничений на длину данных, с которыми можно работать, единственное ограничение это объем памяти вашей системы.
После сохранения данных в переменной можно делать с ними все что угодно. Давайте проверим, входит ли в число «Пи» дата вашего дня рождения. Напишем небольшую программу, которая будет читать файл и проверять входит ли дата день рождения в первый миллион числа «Пи»:
with open(‘pi_1000000.txt‘) as file_pi:
digits = file_pi.read()
birthday = input(«Введите дату дня рождения: «)
if birthday in digits:
print(«Ваш день рождение входит в число ‘Пи'»)
else:
print(«Ваш день рождение не входит в число ‘Пи'»)
Начало программы не изменилось, читаем файл и сохраняем данные в переменной digits. Далее запрашиваем данные от пользователя с помощью функции input и сохраняем в переменную birstday. Затем проверяем вхождение birstday в digits с помощью команды if-else. Запустив несколько раз программу, получим результат:
Введите дату дня рождения: 260786
Ваш день рождение не входит в число ‘Пи’
Введите дату дня рождения: 260884
Ваш день рождение входит в число ‘Пи’
В зависимости от введенных данных мы получили результат вхождения или не вхождения дня рождения в число «Пи»
Важно: Читая данные из текстового файла, Python интерпретирует весь текст как строку. Если вы хотите работать с ним в числовом контексте, то преобразуйте данные в целое число функцией int() или в вещественное число функцией float().
1.3. Анализ текста из файла на Python
Python может анализировать текстовые файлы, содержащие целые книги. Возьмем книгу «Алиса в стране чудес» и попробуем подсчитать количество слов в книге. Текстовый файл с книгой можете скачать здесь(‘ alice ‘) или загрузить любое другое произведение. Напишем простую программу, которая подсчитает количество слов в книге и сколько раз повторяется имя Алиса в книге.
filename = ‘alice.txt’
with open(filename, encoding=’utf-8′) as file:
contents = file.read()
n_alice = contents.lower().count(‘алиса’)
words = contents.split()
n_words = len(words)
print(f»Книга ‘Алиса в стране чудес’ содержит {n_words} слов.»)
print(f»Имя Алиса повторяется {n_alice} раз.»)
При открытии файла добавился аргумент encoding=’utf-8′. Он необходим, когда кодировка вашей системы не совпадает с кодировкой читаемого файла. После чтения файла, сохраним его в переменной contents.
Для подсчета вхождения слова или выражений в строке можно воспользоваться методом count(), но прежде привести все слова к нижнему регистру функцией lower(). Количество вхождений сохраним в переменной n_alice.
Чтобы подсчитать количество слов в тексе, воспользуемся методом split(), предназначенный для построения списка слов на основе строки. Метод split() разделяет строку на части, где обнаружит пробел и сохраняет все части строки в элементах списка. Пример метода split():
title = ‘Алиса в стране чудес’
print(title.split())
[‘Алиса’, ‘в’, ‘стране’, ‘чудес’]
После использования метода split(), сохраним список в переменной words и далее подсчитаем количество слов в списке, с помощью функции len(). После подсчета всех данных, выведем на экран результат:
Книга ‘Алиса в стране чудес’ содержит 28389 слов.
Имя Алиса повторяется 419 раз.
2.1. Запись в пустой файл в Python
Самый простой способ сохранения данных, это записать их в файл. Чтобы записать текс в файл, требуется вызвать open() со вторым аргументом, который сообщит Python что требуется записать файл. Пример программы записи простого сообщения в файл на Python:
filename = ‘memory.txt’
with open(filename, ‘w’) as file:
file.write(«Язык программирования Python»)
Для начала определим название и тип будущего файла и сохраним в переменную filename. Затем при вызове функции open() передадим два аргумента. Первый аргумент содержит имя открываемого файла. Второй аргумент ‘ w ‘ сообщает Python, что файл должен быть открыт в режиме записи. Во второй строчке метод write() используется для записи строки в файл. Открыв файл ‘ memory.txt ‘ вы увидите в нем строку:
Язык программирования Python
Получившийся файл ничем не отличается от любых других текстовых файлах на компьютере, с ним можно делать все что угодно.
Важно: Открывая файл в режиме записи ‘ w ‘, если файл уже существует, то Python уничтожит его данные перед возвращением объекта файла.
Файлы можно открывать в режимах:
- чтение ‘ r ‘
- запись ‘ w ‘
- присоединение ‘ a ‘
- режим как чтения, так и записи ‘ r+ ‘
2.2. Многострочная запись в файл на Python
При использовании функции write() символы новой строки не добавляются в записываемый файл:
filename = ‘memory.txt’
with open(filename, ‘w’) as file:
file.write(«Язык программирования Python»)
file.write(«Язык программирования Java»)
file.write(«Язык программирования Perl»)
В результате открыв файл мы увидим что все строки склеились:
Язык программирования PythonЯзык программирования JavaЯзык программирования Perl
Для написания каждого сообщения с новой строки используйте символ новой строки n
filename = ‘memory.txt’
with open(filename, ‘w’) as file:
file.write(«Язык программирования Pythonn«)
file.write(«Язык программирования Javan«)
file.write(«Язык программирования Perln«)
Результат будет выглядеть так:
Язык программирования Python
Язык программирования Java
Язык программирования Perl
2.3. Присоединение данных к файлу на Python
Для добавления новых данных в файл, вместо того чтобы постоянно перезаписывать файл, откройте файл в режиме присоединения ‘ a ‘. Все новые строки добавятся в конец файла. Возьмем созданный файл из раздела 2.2 ‘memory.txt’. Добавим в него еще пару строк.
filename = ‘memory.txt’
with open(filename, ‘a’) as file:
file.write(«Hello worldn»)
file.write(«Полет на лунуn»)
В результате к нашему файлу добавятся две строки:
Язык программирования Python
Язык программирования Java
Язык программирования Perl
Hello world
Полет на луну
3. Исключения в Python
При выполнении программ могут возникать ошибки, для управления ими Python использует специальные объекты, называемые исключениями. Когда в программу включен код обработки исключения, ваша программа продолжится, а если нет, то программа остановится и выведет трассировку с отчетом об исключении. Исключения обрабатываются в блоках try-except. С блоками try-except программы будут работать даже в том случае, если что-то пошло не так.
3.1. Блоки try-except на Python
Приведем пример простой ошибки деления на ноль:
print(7/0)
Traceback (most recent call last):
File «example.py», line 1, in <module>
print(7/0)
ZeroDivisionError: division by zero
Если в вашей программе возможно появление ошибки, то вы можете заранее написать блок try-except для обработки данного исключения. Приведем пример обработки ошибки ZeroDivisionError с помощью блока try-except:
try:
print(7/0)
except ZeroDivisionError:
print(«Деление на ноль запрещено»)
Команда print(7/0) помещена в блок try. Если код в блоке try выполняется успешно, то Python пропускает блок except. Если же код в блоке try создал ошибку, то Python ищет блок except и запускает код в этом блоке. В нашем случае в блоке except выводится сообщение «Деление на ноль запрещено». При выполнение этого кода пользователь увидит понятное сообщение:
Деление на ноль запрещено
Если за кодом try-except следует другой код, то Python продолжит выполнение программы.
3.2. Блок try-except-else на Python
Напишем простой калькулятор, который запрашивает данные у пользователя, а затем результат деления выводит на экран. Сразу заключим возможную ошибку деления на ноль ZeroDivisionError и добавим блок else при успешном выполнение блока try.
while True:
first_number = input(«Введите первое число: «)
if first_number == ‘q’:
break
second_number = input(«Введите второе число: «)
if second_number == ‘q’:
break
try:
a = int(first_number) / int(second_number)
except ZeroDivisionError:
print(«Деление на ноль запрещено»)
else:
print(f»Частное двух чисел равно {a}»)
Программа запрашивает у пользователя первое число (first_number), затем второе (second_number). Если пользователь не ввел » q « для завершения работы программа продолжается. В блок try помещаем код, в котором возможно появление ошибки. В случае отсутствия ошибки деления, выполняется код else и Python выводит результат на экран. В случае ошибки ZeroDivisionError выполняется блок except и выводится сообщение о запрете деления на ноль, а программа продолжит свое выполнение. Запустив код получим такие результаты:
Введите первое число: 30
Введите второе число: 5
Частное двух чисел равно 6.0
Введите первое число: 7
Введите второе число: 0
Деление на ноль запрещено
Введите первое число: q
В результате действие программы при появлении ошибки не прервалось.
3.3. Блок try-except с текстовыми файлами на Python
Одна из стандартных проблем при работе с файлами, это отсутствие необходимого файла, или файл находится в другом месте и Python не может его найти. Попробуем прочитать не существующий файл:
filename = ‘alice_2.txt’
with open(filename, encoding=’utf-8′) as file:
contents = file.read()
Так как такого файла не существует, Python выдает исключение:
Traceback (most recent call last):
File «example.py», line 3, in <module>
with open(filename, encoding=’utf-8′) as file:
FileNotFoundError: [Errno 2] No such file or directory: ‘alice_2.txt’
FileNotFoundError — это ошибка отсутствия запрашиваемого файла. С помощью блока try-except обработаем ее:
filename = ‘alice_2.txt’
try:
with open(filename, encoding=’utf-8′) as file:
contents = file.read()
except FileNotFoundError:
print(f»Запрашиваемый файл {filename } не найден»)
В результате при отсутствии файла мы получим:
Запрашиваемый файл alice_2.txt не найден
3.4. Ошибки без уведомления пользователя
В предыдущих примерах мы сообщали пользователю об ошибках. В Python есть возможность обработать ошибку и не сообщать пользователю о ней и продолжить выполнение программы дальше. Для этого блок try пишется, как и обычно, а в блоке except вы прописываете Python не предпринимать никаких действий с помощью команды pass. Приведем пример ошибки без уведомления:
ilename = ‘alice_2.txt’
try:
with open(filename, encoding=’utf-8′) as file:
contents = file.read()
except FileNotFoundError:
pass
В результате при запуске этой программы и отсутствия запрашиваемого файла ничего не произойдет.
Далее: Функции json. Сохранение данных Python
Назад: Классы в Python
При выполнении компиляции нужно стандартный вывод ошибок направить в файл «error.txt», НО, при этом в терминал тоже должен быть этот же вывод:
g++ test.cpp -o test 2>> error.txt
-
Вопрос заданболее трёх лет назад
-
1114 просмотров
Именно ошибок ? тогда проще всего в файл, а потом его прочитать
а если всего подряд, тогда
g++ test.cpp -o test 2>&1 | Tee-Object -Filepath error.txt
Нашёл ещё вариант
invoke-command { 'txt1'; write-error 'err'; 'txt2' } -ErrorVariable e
#пример вызова внешней команды
invoke-command { python 1.py 2>&1 } -ErrorVariable e
$e | Out-File error.txt
Пригласить эксперта
-
Показать ещё
Загружается…
12 июн. 2023, в 15:01
5000 руб./за проект
12 июн. 2023, в 14:55
2500 руб./за проект
12 июн. 2023, в 14:52
3500 руб./за проект
Минуточку внимания
cl0oud 1 / 1 / 1 Регистрация: 17.11.2009 Сообщений: 56 |
||||
1 |
||||
если нет файла, то вывод ошибки03.06.2011, 13:16. Показов 2996. Ответов 5 Метки нет (Все метки)
где ошибка, что делать?
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
03.06.2011, 13:16 |
Ответы с готовыми решениями: Добавить условие на вывод ошибки, если нет пробела в строке Предусмотреть вывод ошибки, если файла не существует #define… В поиске добавить код если нет такого значения в стринггрид то вывести ошибку такого значения нет, если находит то вывод Автозапуск Access с параметром, и вывод отчета если в нем есть данные, если нет, то закрытие приложения 5 |
Para bellum 5750 / 4131 / 1506 Регистрация: 06.01.2011 Сообщений: 11,279 |
||||||||
03.06.2011, 13:51 |
2 |
|||||||
Попробуйте заменить указанный вами код на такой, будет удобней:
Или измените на седьмой строке указанного вами кода вопросительный знак на
1 |
cl0oud 1 / 1 / 1 Регистрация: 17.11.2009 Сообщений: 56 |
||||
03.06.2011, 14:06 [ТС] |
3 |
|||
файл то есть, мне вывод содержимого надо было,
0 |
Para bellum 5750 / 4131 / 1506 Регистрация: 06.01.2011 Сообщений: 11,279 |
||||
03.06.2011, 14:24 |
4 |
|||
Если я вас правильно понял, то вот вам код, который выводит содержимое файла:
Просто замените ваш код этим.
1 |
1 / 1 / 1 Регистрация: 17.11.2009 Сообщений: 56 |
|
03.06.2011, 15:19 [ТС] |
5 |
В моём случае выводилось всё как в файле, т.е содержимое файла и абзацы. К сожалению, в вашем случае выводит весь файл не соблюдая абзацы, в чём прикол?)
0 |
andyarus 174 / 76 / 2 Регистрация: 19.04.2011 Сообщений: 322 |
||||
03.06.2011, 15:27 |
6 |
|||
1 |
Данная глава посвящена одному из важнейших аспектов PHP — средствам файлового ввода/вывода. Как нетрудно предположить, входные и выходные потоки данных интенсивно используются при разработке web-приложений. Не ограничиваясь простым чтением/записью файлов, PHP предоставляет в распоряжение программиста средства просмотра и модификации серверной информации, а также запуска внешних программ. Этим средствам и посвящена настоящая глава.
Проверка существования и размера файла
Прежде чем пытаться работать с файлом, желательно убедиться в том, что он существует. Для решения этой задачи обычно используются две функции:
file_exists( ) и is_file( ).
file_exists( )
Функция f ilе_ех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!");
Следующий фрагмент открывает подключение к сайту PHP (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 Sfile does not exist!";
endif;
Запись в файл
С открытыми файлами выполняются две основные операции — чтение и запись.
is_writeable( )
Функция is_writeable( ) позволяет убедиться в том, что файл существует и для него разрешена операция записи. Возможность записи проверяется как для файла, так и для каталога. Синтаксис функции is_writeable( ):
bool is_writeable (string файл)
Одно важное обстоятельство: скорее всего, PHP будет работать под идентификатором пользователя, используемым web-сервером (как правило, «nobody»). Пример использования 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 not open Sfilename for writing"; endif; ?>
Функция fputs( ) является псевдонимом fwrite( ) и может использоваться всюду, где используется fwrite( ).
fputs( )
Функция fputs( ) является псевдонимом fwrite( ) и имеет точно такой же синтаксис. Синтаксис функции fputs( ):
int fputs(int манипулятор, string переменная [, int длина])
Лично я предпочитаю использовать fputs( ). Следует помнить, что это всего лишь вопрос стиля, никак не связанный с какими-либо различиями между двумя функциями.
Чтение из файла
Несомненно, чтение является самой главной операцией, выполняемой с файлами. Ниже описаны некоторые функции, повышающие эффективность чтения из файла. Синтаксис этих функций практически точно копирует синтаксис аналогичных функций записи.
is_readable( )
Функция i s_readable( ) позволяет убедиться в том, что файл существует и для него разрешена операция чтения. Возможность чтения проверяется как для файла, так и для каталога. Синтаксис функции is_readable( ):
boo! is_readable (string файл]
Скорее всего, PHP будет работать под идентификатором пользователя, используемым web-сервером (как правило, «nobody»), поэтому для того чтобы функция is_readable( ) возвращала TRUE, чтение из файла должно быть разрешено всем желающим. Следующий пример показывает, как убедиться в том, что файл существует и доступен для чтения:
if ( is_readable($filename) ) :
// Открыть файл и установить указатель текущей позиции в конец файла
$fh = fopen($filename, "r");
else :
print "$filename is 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-purpose flour
3/4 stick (6 tablespoons) unsalted butter, chopped
2 tablespoons vegetable shortening 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 и PHP:
string fgetss (Int манипулятор, int длина [, string разрешенные_теги])
Прежде чем переходить к примерам, ознакомьтесь с содержимым листинга 7.2 — этот файл используется в листингах 7.3 и 7.4.
Листинг 7.2. Файл science.html
<html>
<head>
<title>Breaking News - Science</title>
<body>
<h1>Alien lifeform discovered</h1><br>
<b>August 20. 2000</b><br>
Early this morning, a strange new form of fungus was found growing in the closet of W. J. Gilmore's old apartment refrigerator. It is not known if powerful radiation emanating from the tenant's computer monitor 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 - Science Alien lifeform discovered August 20. 2000 Early this morning, a strange new form of fungus was found growing in the closet of W. J. Gilmore's old apartment refrigerator. It is not known if powerful radiation emanating from the tenant's computer 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 - Science Alien lifeform discovered August 20. 2000 Early this morning, a strange new form of fungus was found growing in the closet of W. J. Gilmore's old apartment refrigerator. It is not known if powerful radiation emanating from the tenant's computer 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: Pastry Dough
Line 1: 1 1/4 cups all-purpose flour
Line 2: 3/4 stick (6 tablespoons) unsalted butter, chopped
Line 3: 2 tablespoons vegetable shortening
Line 4: 1/4 teaspoon salt
Line 5: 3 tablespoons water
Перенаправление файла в стандартный выходной поток
Функция readfile( ) читает содержимое файла и направляет его в стандартный вывод (в большинстве случаев — в браузер). Синтаксис функции readfile( ):
int readfile (string файл [, int включение_пути])
Функция возвращает количество прочитанных байтов. Файл может находиться в локальной файловой системе, существовать в виде стандартного потока ввода/вывода или представлять файл в удаленной системе, принимаемой средствами HTTP или FTP. Параметр файл задается по тем же правилам, что и в функции fopen( ).
Предположим, у вас имеется файл latorre.txt, содержимое которого вы хотите вывести в браузере:
Restaurant «La Тоrrе.» located in Nettuno, Italy, offers an eclectic blend of style. history, and fine seafood cuisine. Within the walls of the medieval borgo surrounding the city, one can dine while watching the passersby shop in the village boutiques. Comfort coupled with only the freshest seafare make La Torre one 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, rosemaryn");
fputs($fh, "Paprika, salt, peppern");
fputs($fh, "Basil, sage, gingern");
// Закрыть манипулятор
fclose($fh);
// Открыть процесс UNIX grep для поиска слова Basil в файле spices.txt
$fh - popen("grep Basil < spices.txt", "r");
// Вывести результат работы grep
fpassthru($fh);
?>
Результат выглядит так:
Basil, sage, ginger
Функция fpassthru( ) является аналогом функции passthru( ), рассматриваемой в разделе «Запуск внешних программ» этой главы.
pclose( )
После выполнения всех операций файл или процесс необходимо закрыть. Функция pclose( ) закрывает соединение с процессом, заданным манипулятором, по аналогии с тем, как функция fclose( ) закрывает файл, открытый функцией fopen( ). Синтаксис функции pclose( ):
int pclose (int манипулятор}
В параметре манипулятор передается манипулятор, полученный ранее при успешном вызове рореn( ).
Открытие соединения через сокет
PHP не ограничивается взаимодействием с файлами и процессами — вы также можете устанавливать соединения через сокеты. Сокет (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.1rn");
fputs ($fp, "Host: $hostrnrn"); $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.htm Date: Sat. 19 Aug 2000 23:03:25 GMT Content-Type: text/html Accept-Ranges: bytes Last-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( ).
Запуск внешних программ
Сценарии PHP также могут выполнять программы, находящиеся на сервере. Такая возможность особенно часто используется при администрировании системы через web-браузер, а также для более удобного получения сводной информации о системе.
ехес( )
Функция ехес( ) запускает заданную программу и возвращает последнюю строку ее выходных данных. Синтаксис функции ехес( ):
string exec (string команда [, string массив [, int возврат]])
Обратите внимание: функция ехес( ) только выполняет команду, не выводя результатов ее работы. Все выходные данные команды можно сохранить в необязательном параметре массив. Кроме того, если при заданном параметре массив также задается переменная возврат, последней присваивается код возврата выполненной команды.
Листинг 7.7 показывает, как использовать функцию ехес( ) для выполнения системной функции UNIX ping.
Листинг 7.7. Проверка связи с сервером с применением функции ехес( )
<?
exec("ping -с 5 www.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=243 time=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 from 208.247.106.187: icmp_seq=3 ttl=243 time=55.339 ms 64 bytes from 208.247.106.187: icmp_seq=4 ttl=243 time=69.865 ms -- www.php.net ping statistics -- 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, поэтому я посвятил целую главу этой теме и ее отношению к программированию PHP. За дополнительной информацией обращайтесь к главе 16.
Работа с файловой системой
В PHP существуют функции для просмотра и выполнения различных операций с файлами на сервере. Информация об атрибутах серверных файлов (местонахождение, владелец и привилегии) часто бывает полезной.
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 "Last modified: ".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 access time: $atime <br>";
print "Last modification 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).
Все эти характеристики можно изменить при помощи соответствующих функций PHP. Функции, описанные в этом разделе, не работают в системах семейства 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 имя_файла)
Копирование и переименование файлов
К числу других полезных системных функций, которые могут выполняться в сценариях PHP, относятся копирование и переименование файлов на сервере. Эти операции выполняются двумя функциями: сору( ) и rename( ).
сору( )
Скопировать файл в сценарии PHP ничуть не сложнее, чем при помощи команды UNIX ср. Задача решается функцией PHP сору( ). Синтаксис функции сору( ):
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 файл)
Если вы работаете с PHP в системе Windows, при использовании этой функции иногда возникают проблемы. В этом случае можно воспользоваться описанной выше функцией system( ) и удалить файл командой DOS del:
system ("del filename.txt");
Работа с каталогами
Функции PHP позволяют просматривать содержимое каталогов и перемещаться по ним. В листинге 7.8 изображена типичная структура каталогов в системе UNIX.
Листинг 7.8. Типичная структура каталогов
drwxr-xr-x 4 root wheel 512 Aug 13 13:51 book/
drwxr-xr-x 4 root wheel 512 Aug 13 13:51 code/
-rw-r--r-- 1 root wheel 115 Aug 4 09:53 index.html
drwxr-xr-x 7 root wheel 1024 Jun 29 13:03 manual/
-rw-r--r-- 1 root wheel 19 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("Could not 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, просмотрите алгоритм, написанный на псевдокоде:
- Присвоить переменной $access имя файла, в котором будет храниться значение счетчика.
- Использовать функцию filе( ) для чтения содержимого $access в массив $visits. Префикс @ перед именем функции подавляет возможные ошибки (например, отсутствие файла с заданным именем).
- Присвоить переменной $current_visitors значение первого (и единственного) элемента массива $visits.
- Увеличить значение $current_visitors на 1.
- Открыть файл $access для записи и установить указатель текущей позиции в начало файла.
- Записать значение $current_visitors в файл $access.
- Закрыть манипулятор, ссылающийся на файл $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, строит карту сайта — иерархическое изображение всех папок и файлов на сервере, начиная с заданного каталога. При вычислении отступов элементов, из которых состоит карта сайта, используются функции, определенные в этой и предыдущих главах. Прежде чем переходить к программе, просмотрите алгоритм, написанный на псевдокоде:
- Объявить служебные переменные для хранения родительского каталога, имени графического файла с изображением папки, названия страницы и флага серверной ОС (Windows или другая система).
- Объявить функцию display_directory( ), которая читает содержимое каталога и форматирует его для вывода в браузере.
- Построить путь к каталогу объединением имени, передаваемого в переменной $dir1, с $dir.
- Открыть каталог и прочитать его содержимое. Отформатировать имена каталога и файлов и вывести их в браузере.
- Если текущий файл является каталогом, рекурсивно вызвать функцию display_di rectory( ) и передать ей имя нового каталога для вывода. Вычислить отступ, используемый при форматировании вывода.
Если файл не является каталогом, он форматируется для отображения в виде гиперссылки (а также вычисляется отступ, используемый при форматировании).
Листинг 7.10. Программа sitemap.php
// Файл: sitemap.php // Назначение: построение карты сайта // Каталог, с которого начинается построение карты $beg_path = "C:Program FilesVApache GroupApachehtdocsphprecipes"; // Файл с графическим изображением папки. // Путь должен задаваться Относительно* корневого каталога сервера Apache $folder_location = "C:My DocumentsPHP for ProgrammersFINAL CHPSgraphicsfolder.gif"; // Текст в заголовке окна $page_name = "PHPRecipes SiteMap"; // В какой системе будет использоваться сценарий - Linux или Windows? // (0 - Windows; 1 - Linux) $usingjinux = 0; // Функция: display_directory // Назначение: чтение содержимого каталога, определяемого параметром // $dir1, с последующим форматированием иерархии каталогов и файлов. // Функция может вызываться рекурсивно. function display_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 " "; $х++; endwhile; print "<img src="$folder_location" alt="[dir]"> ".basename($file)."<br>"; // Увеличить счетчик // Рекурсивный вызов функции 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 " "; $x++; endwhile: print "<a href = "" .$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 изображен результат выполнения сценария для каталога с несколькими главами этой книги.
Итоги
В этой главе были представлены многие средства PHP, предназначенные для работы с файлами. В частности, мы рассмотрели следующие вопросы:
- проверку существования файлов;
- открытие и закрытие файлов и потоков ввода/вывода;
- запись в файл и чтение из него;
- перенаправление файла в выходной поток;
- запуск внешних программ;
- операции с файловой системой.
Материал этой главы подготовил почву для следующей главы, «Строки и регулярные выражения», поскольку при разработке web-приложений обработка строк и операции ввода/вывода очень тесно связаны.