Функция CreateRightsDir создает каталог в файловой системе сервера (сайта) и определяет права каталога для владельца, для его группы и всех остальных пользователей.
Если каталог уже существует, то функция только выполняет попытку переопределить права. В завершение работы функция сравнивает права, которые установились, с заявленными правами, а именно с правами, которые должны были установиться. Если желание не совпадает с фактом, то выдается сообщение об ошибке или формируется исключение.
Имя каталога задается по спецификации, то есть имя задается вместе с относительным или абсолютным путем, например:
$imgDir="Gallery"; здесь явно путь не указан, поэтому новый каталог "Gallery"
создается в каталоге из которого запущен текущий PHP-сценарий.
$ImgDir=$_SERVER['DOCUMENT_ROOT'].'/Gallery'; здесь новый каталог "Gallery"
создается в корневом каталоге сайта.
Права определяются в традиционной нотации через трех-четырехразрядное восьмеричное число, задающее режим доступа к каталогу для владельца каталога, для группы, в которую входит владелец, и для прочих пользователей.
Права передаются через биты соответствующих восьмеричных разрядов числа:
OCT | BIN | Маска | Права на каталог |
---|---|---|---|
0 | 000 | - - - | доступ к каталогу и его подкаталогам запрещен, ничего нельзя делать |
1 | 001 | - - x | можно выполнить двоичный файл о существовании которого известно пользователю, зайти или прочитать каталог запрещено |
2 | 010 | - w - | отсутствие прав |
3 | 011 | - w x | можно добавить, удалить, изменить файл каталога. Прочитать содержимое каталога невозможно |
4 | 100 | r - - | можно прочитать содержимое каталога, узнать имена файлов, там лежащих |
5 | 101 | r - x | можно зайти в каталог, прочитать его содержимое, посмотреть атрибуты файлов, удалять или добавлять файлы нельзя |
6 | 110 | r w - | можно изменить файл каталога, удалять или добавлять файлы нельзя |
7 | 111 | r w x | можно читать файлы, удалять их, добавлять новые, изменять файлы, сделать каталог текущим |
Для полноценного просмотра каталога, необходимы права на чтение каталога и доступ к файлам, а главное к их атрибутам, то есть минимальные разумные права на каталог 5 (r-x). Прав 4 (r--) хватит только на просмотр имен файлов, без атрибутов и не будут известны ни размер файла, ни права доступа. На практике для каталогов используется только три режима: 7 (rwx), 5 (r-x) и 0 (---).
Например, при вызове функции CreateRightsDir следующим образом:
$ImgDir=$_SERVER['DOCUMENT_ROOT'].'/CreateRightsDir';установятся права: "d rwx r-x r-x".
Очень любопытный режим доступа к каталогу - 3 (-wx): он позволяет делать в директории все, что угодно, но не позволяет прочитать имена объектов. То есть если вам не известны названия объектов в этом каталоге, то вы сделать с ними ничего не сможете (даже удалить по маске *, так как маску не к чему применять - имена недоступны).
При работе с каталогами сервера, основанного на Unix, можно использовать старший четвертый восьмеричный разряд, управляя битами SUID, SGID, Sticky.
SUID (Set User ID - бит смены идентификатора пользователя) и SGID (Set Group ID - бит смены идентификатора группы). Если установить SGID для каталога, то все файлы созданные в нем при запуске будут принимать идентификатор группы каталога, а не группы владельца, который создал файл в этом каталоге. Аналогично SUID. Одним словом, если пользователь поместил исполняемый файл в такой каталог, запустив его, процесс запустится от имени владельца (группы) каталога, в котором лежит этот файл.
Установка Sticky-бита на каталог означает, что удалить файл из этого каталога сможет только владелец файла или суперпользователь. Другие пользователи лишаются права удалять файлы.
Это правило будет действовать и при вызове функции CreateRightsDir с установкой каждого бита "d rws rws rwt" следующим образом:
$ImgDir=$_SERVER['DOCUMENT_ROOT'].'/CreateRightsDir';
<?php namespace prown;
// PHP7/HTML5, EDGE/CHROME *** CreateRightsDir.php ***
// ****************************************************************************
// * TPhpPrown Создать каталог (проверить существование) *
// * и задать его права *
// * *
// * v1.2, 24.12.2021 Автор: Труфанов В.Е. *
// * Copyright © 2018 tve Дата создания: 08.12.2021 *
// ****************************************************************************
// Синтаксис:
//
// $Result=CreateRightsDir($Dir,$modeDir=0777,$ModeError=rvsTriggerError);
//
// Параметры:
//
// $Dir - спецификация создаваемого каталога, то есть абсолютный или
// относительный путь к каталогу и имя каталога;
// $modeDir - параметр назначения прав каталога. Это восьмеричное число,
// состоящее из четырех цифр: первая цифра всегда равна нулю (так как
// указывает восьмеричное число); вторая цифра указывает разрешения для
// владельца каталога; третья цифра указывает разрешения для группы
// пользователей владельца; четвертая цифра указывает разрешения для всех
// остальных. Возможные значения: 1 = выполнение, 2 = право на запись,
// 4 = разрешения на чтение (суммы значений дают возможность установить
// несколько разрешений)
//
// rwx --- --- => $modeDir=700, только владелец может входить в этот
// каталог, читать и записывать в него файлы
//
// rwx r-x r-x => $modeDir=755, любой пользователь может входить в этот
// каталог и читать содержимое каталога, но изменять
// содержимое может только владелец
//
// $ModeError - режим вывода сообщений об ошибке (по умолчанию сообщение
// выводится через исключение с пользовательской ошибкой на сайте
// doortry.ru)
//
// Возвращаемое значение:
//
// $Result - текст сообщения об ошибке (string) при $ModeError=rvsReturn;
// false в случае неуспешного выполнения функции;
// true - в случае успешного выполнения функции
//
// Зарегистрированные ошибки/исключения:
//
// DirСreateError - "Ошибка создания каталога". Функция дополнительно
// сбрасывает детальные данные об ошибках в лог-файл (фиксируются следующие
// события:
// DirNameIncorrect - "Неверно указано название каталога";
// NoErrReporting - "Указан оператор @, ошибки отключены";
// NonWellNumeric - "Некорректное числовое значение в правах каталога";
// DirRightsNoAssign - "Ошибка назначения прав каталога";
// NoDeterminRights - "Ошибка определения прав каталога";
// RightsDonotMatch - "Установленные и желаемые права не совпадают".
require_once 'iniConstMem.php';
require_once 'iniErrMessage.php';
require_once 'MakeUserError.php';
require_once 'ViewPerms.php';
// ****************************************************************************
// * Создать каталог (проверить существование) и задать его права *
// ****************************************************************************
function CreateRightsDir($Dir,$modeDir=0777,$ModeError=rvsTriggerError)
// https://habr.com/ru/sandbox/124577/ - статья про удаление каталога
// https://advancedhosters.com/ru/chmod - статья по правам каталога или файла
{
$Result=true;
// Если каталога нет, то будем создавать его
clearstatcache(true,$Dir); // сбросили кэш состояния файла
if (!is_dir($Dir))
{
// Обыгрываем возможные ошибки создания каталога:
// задаём пользовательский обработчик ошибок, запускаем функцию создания
// каталога, восстанавливаем прежний обработчик ошибок
set_error_handler("prown\CreateRightsMkdirHandler");
$is=mkdir($Dir,$modeDir);
restore_error_handler();
// Так как возникла ошибка создания каталога, то выводим сообщение
if (!$is)
{
// Отмечаем ошибку создания каталога - Directory creation error по
// одной из причин: а) неправильно указана спецификация каталога
// (например, в пути или в названии каталога присутствуют запрещенные
// символы); б) ...
$Result=MakeUserError(DirСreateError.': '.$Dir,'TPhpPrown',$ModeError);
if ($ModeError<>rvsReturn) $Result=false;
}
}
// Каталог есть, сравниваем заявленные и установленные права
clearstatcache(true,$Dir); // сбросили кэш состояния файла
if (is_dir($Dir))
{
// Инициируем строковые представления заявленных и установленных прав
$fPermissions='-1'; $xPermissions='-2';
// Определяем и сравниваем строки с заявленными и установленными правами
$is=getFilePerms($Dir,$modeDir,$fPermissions,$xPermissions);
// Если права совпали, то с успехом завершаем работу
if ($fPermissions===$xPermissions)
{
// ConsoleLog('Установленные и желаемые права совпали с первого раза');
}
// Права не совпали, предполагаем, что находимся в Windows,
// будем устанавливать права отдельно
else
{
// Обыгрываем возможные ошибки задания прав каталога:
set_error_handler("prown\CreateRightsChmodHandler");
clearstatcache(true,$Dir); // сбросили кэш состояния файла
$is=chmod($Dir,$modeDir);
restore_error_handler();
// Так как возникла ошибка задания прав, то выводим сообщение
if (!$is)
{
$Result=MakeUserError(DirRightsNoAssign.'[onerror]: '.$Dir,'TPhpPrown',$ModeError);
if ($ModeError<>rvsReturn) $Result=false;
}
// Ошибки задания прав нет, поэтому повторно определяем и сравниваем
// строки с заявленными и установленными правами
else
{
// Инициируем строковые представления заявленных и установленных прав
$fPermissions='-3'; $xPermissions='-4';
// Определяем и сравниваем строки с заявленными и установленными правами
$is=getFilePerms($Dir,$modeDir,$fPermissions,$xPermissions);
// Завершаем работу, если установленные и желаемые права совпадают
if ($fPermissions===$xPermissions) {}
// Отмечаем ошибку, если установленные и желаемые права НЕ совпадают
else
{
$Result=MakeUserError(RightsDonotMatch.': '.
$fPermissions.'<>'.$xPermissions,'TPhpPrown',$ModeError);
if ($ModeError<>rvsReturn) $Result=false;
}
}
}
}
return $Result;
}
// ****************************************************************************
// * Получить строки с установленными и заявленными правами *
// ****************************************************************************
function getFilePerms($Dir,$modeDir,&$fPermissions,&$xPermissions)
{
$Result=true;
// Формируем строку с заявленными правами
if ($modeDir==0000) $xPermissions='0000';
else $xPermissions='0'.sprintf('%o',$modeDir);
// Если права нулевые, то раздвигаем
clearstatcache(true,$Dir);
// Определяем установленные права и обыгрываем возможные ошибки определения:
set_error_handler("prown\CreateRightsPermsHandler");
$permissions=fileperms($Dir);
restore_error_handler();
// Так как возникла ошибка определения прав, то выводим сообщение
if (!$permissions)
{
$Result=MakeUserError(NoDeterminRights.'[onerror]: '.$Dir,'TPhpPrown',$ModeError);
if ($ModeError<>rvsReturn) $Result=false;
}
// Формируем строку с установленными правами
else
{
$fPermissions=substr(sprintf('%o',$permissions),-4);
// Если задействованы дополнительные биты прав (Unix), добавляем 0 восьмеричности
if (substr($fPermissions,0,1)<>'0') $fPermissions='0'.$fPermissions;
}
return $Result;
}
// ****************************************************************************
// * Обыграть возможные ошибки создания каталога *
// ****************************************************************************
function CreateRightsMkdirHandler($errno,$errstr,$errfile,$errline)
{
$modul='CreateRightsMkdirHandler';
// Если error_reporting нулевой, значит, использован оператор @,
// все ошибки должны игнорироваться
if (!error_reporting())
{
putErrorInfo($modul,$errno,
'['.NoErrReporting.'] '.$errstr,$errfile,$errline);
}
else
{
// Отлавливаем ошибку "Неверно указано название каталога"
// "Directory name is incorrect"
$Find='No such file or directory';
$Resu=Findes('/'.$Find.'/u',$errstr);
if ($Resu==$Find)
{
putErrorInfo($modul,$errno,
'['.DirNameIncorrect.'] '.$errstr,$errfile,$errline);
}
// Обобщаем остальные ошибки
else
{
putErrorInfo($modul,$errno,
'['.DirСreateError.'] '.$errstr,$errfile,$errline);
}
}
}
// ****************************************************************************
// * Обыграть возможные ошибки задания прав каталога *
// ****************************************************************************
function CreateRightsChmodHandler($errno,$errstr,$errfile,$errline)
{
$modul='CreateRightsChmodHandler';
// Отлавливаем ошибку "Некорректное числовое значение в правах каталога"
// "A non well formed numeric value encountered"
$Find='A non well formed numeric value encountered';
$Resu=Findes('/'.$Find.'/u',$errstr);
if ($Resu==$Find)
{
putErrorInfo($modul,$errno,
'['.NonWellNumeric.'] '.$errstr,$errfile,$errline);
}
// Обобщаем остальные ошибки
else
{
putErrorInfo($modul,$errno,
'['.DirRightsNoAssign.'] '.$errstr,$errfile,$errline);
}
}
// ****************************************************************************
// * Обыграть возможные ошибки определения прав каталога *
// ****************************************************************************
function CreateRightsPermsHandler($errno,$errstr,$errfile,$errline)
{
putErrorInfo('CreateRightsPermsHandler',$errno,
'['.NoDeterminRights.'] '.$errstr,$errfile,$errline);
}
// **************************************************** CreateRightsDir.php ***
Сообщения выполненного теста функции