Как гарантировать, что указанный файл является устройством на BSD/Linux с PHP?
Во время работы над проектом, который читает из /dev/urandom
для генерации случайных байтов, было предложено проверить, что /dev/urandom
- это устройство, а не только файл.
Самый простой способ - это что-то вроде:
/**
* Is the given file a device?
*
* @param string|resource $file
* @return boolean
*/
function is_device($file)
{
if (is_resource($file)) {
$stat = fstat($file);
} elseif (is_readable($file) && !is_link($file)) {
$stat = stat($file);
} else {
return false;
}
return $stat['rdev'] !== 0;
}
Мой вопрос в два раза:
- Это лучший способ проверить, что этот файл является устройством?
- Существуют ли случаи, когда проверка
$stat['rdev'] !== 0
может завершиться неудачей?
Важно. Решение, которое мне нужно, должно быть на PHP без каких-либо расширений PECL или пользовательского кода C. Проект чистый PHP 5 polyfill функций PHP 7 random_bytes()
и random_int()
и предназначен для установки в любом другом PHP 5 проектов от Composer.
Ответы
Ответ 1
ну, вы можете использовать filetype().
если вы быстро произнесите уранд, вы увидите:
ll /dev/urandom
crw-rw-rw- 1 root root 1, 9 Jul 26 17:38 /dev/urandom
что 'c' в начале означает, что это "характер" типа файла. вы можете проверить все различные типы файлов здесь:
https://en.wikipedia.org/wiki/Unix_file_types
это означает, что если вы запустите
filetype("/dev/urandom");
вы получите "char" назад, что означает символ filetype. это должно сделать трюк.
Ответ 2
Обновление
Мое первоначальное решение оказалось всего лишь повторной реализацией filetype($filepath) === 'char'
, поэтому filetype()
, похоже, единственное, что вам нужно.
На основе ответа @frymaster...
Я посмотрел, как работает функция PHP stat()
, ища "char" и нашла this.
В сочетании с руководством stat (2) для Linux и FreeBSD, а также комментарий к руководству PHP для stat(), я придумал следующее:
function is_device($filepath)
{
if ( ! file_exists($filepath) OR (stripos(PHP_OS, 'Linux') === false && stripos(PHP_OS, 'BSD') === false))
{
return false;
}
$mode = stat($filepath)['mode'];
return (020000 === ($mode & 0170000));
}
Работает на моей Linux-системе.
Обновить (чтобы ответить на второй вопрос)
Да, stat($file)['rdev'] !== 0
может выйти из строя. Из того, что я нашел, он может вернуть -1, если не поддерживается ОС, хотя даже положительное значение может указывать на другой тип устройства. Его значения также зависят от ОС.