Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Котеров Д. В., Костарев А. Ф. - PHP 5. 2-е издание (В подлиннике) - 2008

.pdf
Скачиваний:
6114
Добавлен:
29.02.2016
Размер:
11.36 Mб
Скачать

334

Часть IV. Стандартные функции PHP

Резюме

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

Вглаве описаны полезные функции: fgetcsv() для считывания и анализа CSV-фай- лов, генерируемых Microsoft Excel, а также parse_ini_file() для работы с INI-фай- лами.

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

Особенное внимание в главе уделено возможностям блокирования файлов при помощи одной-единственной (но очень емкой) функции flock(). Корректная блокировка — вопрос весьма тонкий, без досконального его понимания трудно писать сценарии, работающие без ошибок при сколько-нибудь значительной посещаемости сайта.

ГЛАВА 19

Права доступа и атрибуты файлов

Листинги данной главы можно найти в подкаталоге perm.

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

Современные файловые системы Unix и Windows позволяют ограничить доступ к некоторым файлам для указанных пользователей и групп. Так как Web-програм- мирование — это в основном программирование для Unix, для того чтобы скрипты начали работать, и чтобы избежать проблем с безопасностью в дальнейшем, необходимо понимание основ разграничения прав доступа.

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

КОГДА вы регистрируетесь в системе (например, по SSH или FTP), вашей сессии присваивается так называемый идентификатор пользователя (user ID, UID). В Unix это — целое число, большее нуля для обычного пользователя (с ограниченными правами) и равное нулю — для суперпользователя (администратора).

Чтобы не путаться с числовыми UID, в Unix существует возможность связывать с ними буквенные имена пользователей. После ввода такого имени оно сразу же преобразуется в UID, и в дальнейшем работа ведется уже с числом. Для преобразования используется специальный файл /etc/passwd, хранящий соответствие имен пользователей их идентификаторам. (В Unix традиционно администратор имеет имя root.)

В Windows UID устроен несколько сложнее, но идея все равно та же.

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

Вообще говоря, правильнее было бы сказать, что UID назначается не сессии, а некоторому процессу, который эту сессию реализует (например, FTPили SSH-

336

Часть IV. Стандартные функции PHP

серверу, к которому вы присоединились). Все дочерние процессы, им порождаемые, автоматически наследуют идентификатор, и сменять его им запрещается. В таком случае говорят, что процесс "запущен под пользователем X", где X — это UID пользователя (или его имя, которое в итоге все равно преобразуется в UID).

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

Это объясняет общий механизм того, как работает большинство серверов (демонов) в Unix и Windows. Рассмотрим, например, как работает FTP-сервер. Он запускается с UID =0 (администраторские привилегии) и ждет подключения пользователя. Как только пользователь присоединится к порту, сервер запрашивает у него имя пользователя и пароль, проверяет их, а затем меняет свой UID на UID пользователя. После этого пользователь "общается" уже не с администраторским процессом, а с программой, которой назначен его UID. Это гарантирует, что он не сможет выполнить никаких злонамеренных действий на машине.

Web-сервер (например, Apache) работает точно по такой же схеме. Он ожидает подключений на 80-м порту "под администратором" (как еще говорят, "под рутом", имея в виду пользователя root). Как только получен запрос, адресованный некоторому виртуальному хосту, сервер определяет, какой владелец назначен этому хосту (для этого он использует свой конфигурационный файл — httpd.conf). Далее он переключается на соответствующий UID и запускает обработчик (им может быть PHP, CGIскрипт и т. д.).

Необходимо отметить, что данная техника не поддерживается напрямую стандартным сервером Apache: он всегда запускается и работает с правами фиксированного пользователя (не root), а потому не может менять свой UID. Тем не менее большинство хос- тинг-провайдеров вносят изменения в исходный код сервера с тем, чтобы добавить поддержку описанной выше методики обработки запросов. Все это касается, конечно же, только Unix — в Windows Apache редко используется для целей, отличных от тестовых, а потому чаще всего работает только под администратором.

Итак, после столь длинного вступления становится понятным, что уже самые первые операторы PHP-программы работают под пользователем, отличным от root. А значит, процесс имеет ограниченные привилегии и не может выполнять любые действия с любыми файлами в системе. Давайте посмотрим, как именно ограничиваются права скрипта.

Идентификатор группы

Идентификаторы пользователей могут для удобства объединяться в так называемые группы. Группа в Unix — это просто список UID, имеющий свой собственный иден-

Глава 19. Права доступа и атрибуты файлов

337

тификатор группы (group ID, GID). Как и для UID, для GID может существовать легко запоминающееся буквенное имя группы.

Каждому пользователю обязательно должна быть назначена какая-нибудь группа, которой он принадлежит — это специфика Unix. Для того чтобы лишний раз не ломать голову, часто для каждого пользователя заводят отдельную группу с тем же именем, что и у пользователя.

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

Владелец файла

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

Конечно, суперпользователь может принудительно сменить владельца у любого файла, воспользовавшись командой chown ИмяПользователя ИмяФайла.

Владелец может выполнять со "своим" файлом любые действия: менять атрибуты и дописывать или удалять данные.

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

Файл также имеет и другой атрибут — идентификатор группы (GID). При создании файла он устанавливается равным текущей группе процесса.

Права доступа

Кроме идентификаторов владельца и группы, каждый файл имеет так называемые права доступа (access permissions). Права доступа определяют, какие действия разрешено выполнять с файлом:

его владельцу (user);

пользователю с группой, совпадающей с GID файла (group);

всем остальным пользователям (other).

Что же это за действия? Вот они:

разрешено чтение (r, read);

разрешена запись (w, write);

разрешено исполнение (x, eXecute).

338

Часть IV. Стандартные функции PHP

В Unix действий всего три, однако в Windows их более десятка. Тем не менее три описанных здесь разрешения существуют также и в Windows.

Итак, мы имеем в итоге 9 флагов, объединенных в группу по три. Обычно их изображают так:

user

|

group

|

other

rwx

|

rwx

|

rwx

Или, более коротко:

rwxrwxrwx

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

rwxrwxr-x

Если речь идет о каталоге, то в начало еще приписывают букву d:

drwxrwxr-x

Числовое представление прав доступа

Точно так же, как для имени пользователя и группы существует числовой идентификатор (UID или GID), для прав доступа имеется числовое представление. Обычно права рассматривают как набор из девяти битовых флагов, каждый из которых может принимать значение 0 или 1. Чтобы подчеркнуть логическое разбиение этих флагов на тройки битов, каждую из этих троек представляют одним числом от 0 до 7:

--- — 0

 

 

 

 

 

 

r-- — 4

(= 4*1

+ 2*0

+ 1*0)

r-x —

5

(=

4*1

+

2*0

+

1*1)

rwx —

7

(=

4*1

+

2*1

+

1*1)

Как видно, атрибуту r назначен "вес" 4, атрибуту w — вес 2, атрибуту x — вес 1. Складывая все веса, получаем числовое представление триады.

Но поскольку таких триад у нас три, в итоге получаем число, состоящее из трех цифр:

rwxr-xr-x — 755

rwx------

— 700

Нетрудно заметить, что в итоге у нас получается число в восьмеричной системе счисления — в ней как раз каждое знакоместо может содержать цифру от 0 до 7.

Чтобы подчеркнуть для компилятора или интерпретатора "восьмеричную" природу числа, в программах на PHP, Perl и C его предваряют нулем:

rwxr-xr-x — 0755

rwx------

— 0700

Глава 19. Права доступа и атрибуты файлов

339

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Если вы пропустите этот ведущий ноль, то получится совершенно другое число, потому что оно будет трактоваться в десятичной системе счисления. Например, в двоичном представлении восьмеричное число 0700 выглядит как 111000000 (как нетрудно видеть, это соответствует правам rwx------), в то время как в десятичной это 1010111100 — совершенно не то, что нам нужно (права будут ?-w-rwxr--, где на месте ? — вообще непонятно какой атрибут).

Особенности каталогов

Атрибут x для каталога имеет особое значение. Можно было бы подумать, что он означает разрешение на исполнение файлов внутри его. Однако это не так: данный атрибут — разрешение просмотра атрибутов содержимого каталога.

Чтобы это объяснить, необходимо вначале разобраться, что представляет собой каталог в Unix. Каталог — это обыкновенный файл, в котором содержится список имен файлов и подкаталогов. Для каждого имени приведена ссылка на их физическое положение на диске. Таким образом, можно сказать, что каталог хранит список элементов, каждый из которых представляет собой пару: имя=>физическая_ссылка. Чтобы обратиться к некоторому элементу каталога, нужно, конечно же, знать его физическое положение на диске, а оно может быть получено по его имени.

В каталоге больше ничего нет. В частности, он не хранит непосредственно владельцев и права доступа своих файлов.

Каждый каталог хранит в себе два обязательных элемента, вот они:

элемент с именем "." содержит ссылку на физическое расположение самого каталога. Именно по этой причине пути a/b и a/./././b эквивалентны;

элемент с именем ".." содержит ссылку на родительский каталог. Таким образом, можно сказать, что каждый каталог структурно содержит в себе своего родителя в лице элемента ".." (таким вот оригинальным способом в Unix решается вопрос, что было раньше: курица или яйцо).

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

Атрибут w разрешает создавать, переименовывать и удалять файлы внутри каталога. Заметьте, что не имеет значения, какие права установлены на файл, имя которого меняется (или удаляется). Ведь в каталоге этих сведений нет. Именно поэтому вы можете спокойно удалить из своего домашнего каталога файл, созданный там администратором (например, журнал сервера). С удалением подкаталогов не все так гладко. В самом деле, удаляя каталог dir, вы также удаляете элемент "." в нем. Однако чтобы удалить любой элемент из каталога dir, у вас должны быть права на запись в dir. Их, конечно же, нет — ведь dir создан администратором. В результате в ряде случаев вы можете переименовывать каталоги, но не можете — удалять их.

Кстати, в Windows все обстоит точно таким же образом.

340

Часть IV. Стандартные функции PHP

Атрибут r разрешает вам получить список имен файлов и подкаталогов в каталоге, но не дает сведений о физическом расположении элементов. Можете считать, что атрибут r подобен функции PHP array_keys(): он возвращает все ключи мас- сива-каталога, но не дает нам информации о значениях (физическом положении файлов). А раз нет этой информации, мы и не можем получить доступ к файлам — в самом деле, как мы узнаем, где они располагаются на диске?

Атрибут x как раз позволяет узнать физическое расположение элемента каталога по его имени. Он подобен оператору $array[$name] в PHP, где $array — это мас- сив-каталог, а $name — это имя элемента. Возвращаемое значение — соответственно, физическое положение файла на диске. C помощью этого оператора вы ни за что не сможете узнать, какие же ключи находятся в массиве $array — вы можете только обратиться к элементу с известным именем. Например, вы можете перейти в каталог dir, имеющий атрибут x, при помощи команды Unix cd dir (или вызова chdir("dir") в PHP). Вы также можете просмотреть содержимое файла dir/somefile (если, конечно, права доступа на файл это позволят), ведь информация о физическом положении файла somefile вам известна.

Сложность механизма трактовки атрибутов каталогов, описанного выше, объясняет, почему на практике атрибуты r и x по отдельности встречаются довольно редко. Чаще всего их устанавливают (или снимают) одновременно.

Учтите, что для доступа к файлам внутри каталога на нем обязательно должен стоять хотя бы атрибут x. Например, если файл /home/username/cgi/script.pl имеет права 0777 (максимальные разрешения), а каталог /home/username/ — 0700 (запрет для всех, кроме владельца), файл script.pl все равно никто прочитать не сможет (несмотря на то, что у него, напоминаем, разрешения 0777). Таким образом, хотя права родительского каталога в Unix (в отличие от Windows) не наследуются, они все равно оказывают решающее воздействие на доступ к расположенным внутри него объектам.

Примеры

Рассмотрим несколько типичных примеров того, какие атрибуты назначаются файлам и каталогам. Будем считать, что речь идет о файлах пользователя с UID =10, принадлежащего группе с GID =20.

Домашний каталог пользователя

drwx------

10 20 /home/username/ (= 0700)

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

Защищенный от записи файл

-r--r--r-- 10 20 /home/username/somefile (= 0444)

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

Глава 19. Права доступа и атрибуты файлов

341

себе эти права, потому что владелец волен менять атрибуты своего файла в любое время.

CGI-скрипт

-rwxr-xr-x 10 20 /home/username/cgi-bin/script.pl (= 0755)

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

#!/usr/bin/perl

Обратите внимание на то, что, хотя скрипт и является исполняемым файлом, наличие атрибута r на нем обязательно — одного только x недостаточно! Дело в том, что интерпретатору Perl необходимо вначале прочитать текст программы, и уж только затем он сможет ее выполнить. Для того-то и нужен атрибут r.

Системные утилиты

-rwxr-xr-x 0 0 /bin/mkdir (= 0755)

Команда mkdir — это программа для создания каталогов. Она доступна всем пользователям системы, а потому расположена в каталоге /bin. Как видим, владельцем файла является суперпользователь (UID =0 и GID=0), однако всем пользователям разрешено читать и выполнять данный файл. Таким образом, все пользователи могут создавать у себя каталоги.

Закрытые системные файлы

-r--------

0 0 /etc/shadow (= 0400)

Файл /etc/shadow хранит пароли всех пользователей системы (точнее, их хэш-коды), а потому он имеет максимальную защиту. Никто, кроме администратора (или кроме процессов, запущенных под администратором — это одно и то же), не может просматривать содержимое данного файла.

Взглянув на пример, приведенный выше, может показаться, что root-пользователь не может писать в файл /etc/shadow, однако это не так: суперпользователь имеет максимальные права на любой файл вне зависимости от его атрибутов.

Права доступа на PHP-сценарии

Перейдем к практическому вопросу: какие права доступа должны быть выставлены на PHP-скрипт, чтобы он мог выполняться?

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

342

Часть IV. Стандартные функции PHP

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

Ответ на вопрос о том, надо ли выставлять режим x, зависит от настроек сервера.

Если PHP работает в виде модуля Apache, атрибут x не нужен. Скрипт необходимо располагать в каталоге документов сервера (там же, где и обычные HTMLфайлы). См. гл. 5.

Если PHP настроен в виде CGI-приложения при помощи директив Apache AddHandler и Action, атрибут x также не нужен. См. гл. 5.

Если ваша программа на PHP — обыкновенный CGI-скрипт, имеющий первой строчкой #!/usr/local/bin/php, в этом (и только этом!) случае режим x необходим. Такой способ запуска PHP очень похож на метод, который используется для работы с Perl-скриптами. Соответственно, PHP-сценарии необходимо помещать уже не в каталог документов сервера, а в CGI-каталог — туда же, куда и обычные CGI-скрипты.

Итак, типичные права доступа на PHP-скрипты — rw-r--r-- 0644 (для mod_php или Action-версии) или rwxr-xr-x 755 (для "чистой" CGI-версии или других CGIскриптов).

Функции PHP

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

Права доступа

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

int fileowner(string $filename)

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

bool chown($filename, string $uid)

Делает попытку сменить владельца файла $filename на указанного. Параметр $uid может быть числом (равным UID) или же строкой (содержащей имя пользователя в системе). В случае успеха возвращает true.

Владельца файла может менять только администратор. Так что, скорее всего, в реальных CGI-скриптах данная функция работать не будет.

int filegroup(string $filename)

Возвращает числовой идентификатор группы, владеющей указанным файлом (GID).

Глава 19. Права доступа и атрибуты файлов

343

bool chgrp(string $filename, string $gid)

Данная функция меняет группу для файла $filename. Аргумент $gid может быть числовым представлением GID или же строковым именем группы. Пользователь может менять группу у файлов, которыми он владеет, но не на любую, а только на одну из тех, которой принадлежит сам.

int fileperms(string $filename)

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

bool chmod(string $filename, int $perms)

Функция предназначена для смены прав доступа к файлу $filename. Параметр $perms должен быть целым числом в восьмеричном представлении (например, 0755 для режима rwxr-xr-x — не забудьте о ведущем нуле!).

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

Определение атрибутов файла

array stat(string $filename)

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

0 — устройство;

1 — номер узла inode;

2 — атрибуты защиты файла;

3 — число синонимов (жестких ссылок) файла;

4 — идентификатор UID владельца;

5 — идентификатор GID группы;

6 — тип устройства;

7 — размер файла в байтах;

8 — время последнего доступа в секундах, прошедших с 1 января 1970 года;

9 — время последней модификации содержимого файла;

10 — время последнего изменения атрибутов файла;

11 — размер блока;

12 — число занятых блоков.

Тут вы можете оставить комментарий к выбранному абзацу или сообщить об ошибке.

Оставленные комментарии видны всем.