PHPfileperms()函数

fileperms() 函数是PHP中用于获取文件权限的内置函数。它返回文件的权限位,这些位表示文件的所有者、组和其他用户的读、写和执行权限。

什么是文件权限?

文件权限是Unix/Linux系统中用于控制文件访问的机制。每个文件都有三组权限:所有者(owner)、组(group)和其他用户(others)。每组权限包含读(r)、写(w)和执行(x)三种权限。

语法

int fileperms ( string $filename )

参数说明

参数 描述 类型 是否必需
filename 要检查的文件路径 string

返回值

  • 成功时返回文件的权限(以整数形式)
  • 失败时返回 FALSE
  • 返回值包含文件类型和权限位,需要使用位操作来解析

注意事项

  • 返回值是一个位掩码,需要转换为八进制或符号表示才能理解
  • 返回值的前几位表示文件类型(如普通文件、目录、符号链接等)
  • 使用 substr(sprintf('%o', fileperms($file)), -4) 获取八进制权限
  • 使用 clearstatcache() 清除文件状态缓存以获得最新信息
  • 需要文件读取权限才能获取权限信息

示例代码

示例1:基本使用 - 获取文件权限
<?php
$filename = 'test.txt';

// 获取文件的权限
$perms = fileperms($filename);

if ($perms !== false) {
    echo "文件权限(十进制): " . $perms . "<br>";
    echo "文件权限(八进制): " . sprintf("%o", $perms) . "<br>";
    echo "文件权限(后4位八进制): " . substr(sprintf('%o', $perms), -4);
} else {
    echo "无法获取文件权限";
}
?>
示例2:解析文件权限为符号表示
<?php
function getFilePermissions($filename) {
    if (!file_exists($filename)) {
        return "文件不存在: {$filename}";
    }

    $perms = fileperms($filename);

    // 文件类型
    $type = '';
    switch ($perms & 0xF000) {
        case 0xC000: $type = 's'; break; // 套接字
        case 0xA000: $type = 'l'; break; // 符号链接
        case 0x8000: $type = '-'; break; // 普通文件
        case 0x6000: $type = 'b'; break; // 块设备
        case 0x4000: $type = 'd'; break; // 目录
        case 0x2000: $type = 'c'; break; // 字符设备
        case 0x1000: $type = 'p'; break; // 管道
        default: $type = 'u'; // 未知
    }

    // 所有者权限
    $owner = (($perms & 0x0100) ? 'r' : '-');
    $owner .= (($perms & 0x0080) ? 'w' : '-');
    $owner .= (($perms & 0x0040) ?
                (($perms & 0x0800) ? 's' : 'x') :
                (($perms & 0x0800) ? 'S' : '-'));

    // 组权限
    $group = (($perms & 0x0020) ? 'r' : '-');
    $group .= (($perms & 0x0010) ? 'w' : '-');
    $group .= (($perms & 0x0008) ?
                (($perms & 0x0400) ? 's' : 'x') :
                (($perms & 0x0400) ? 'S' : '-'));

    // 其他用户权限
    $other = (($perms & 0x0004) ? 'r' : '-');
    $other .= (($perms & 0x0002) ? 'w' : '-');
    $other .= (($perms & 0x0001) ?
                (($perms & 0x0200) ? 't' : 'x') :
                (($perms & 0x0200) ? 'T' : '-'));

    return [
        'filename' => $filename,
        'decimal' => $perms,
        'octal_full' => sprintf("%o", $perms),
        'octal_short' => substr(sprintf('%o', $perms), -4),
        'symbolic' => $type . $owner . $group . $other,
        'type' => $type,
        'owner_read' => ($perms & 0x0100) != 0,
        'owner_write' => ($perms & 0x0080) != 0,
        'owner_execute' => ($perms & 0x0040) != 0,
        'group_read' => ($perms & 0x0020) != 0,
        'group_write' => ($perms & 0x0010) != 0,
        'group_execute' => ($perms & 0x0008) != 0,
        'other_read' => ($perms & 0x0004) != 0,
        'other_write' => ($perms & 0x0002) != 0,
        'other_execute' => ($perms & 0x0001) != 0
    ];
}

// 使用示例
$perms_info = getFilePermissions('/etc/passwd');
if (is_array($perms_info)) {
    echo "<h4>文件权限信息:</h4>";
    echo "文件名: {$perms_info['filename']}<br>";
    echo "符号表示: {$perms_info['symbolic']}<br>";
    echo "八进制表示: {$perms_info['octal_short']}<br>";
    echo "完整八进制: {$perms_info['octal_full']}<br>";
    echo "十进制: {$perms_info['decimal']}<br>";

    echo "<h5>详细权限:</h5>";
    echo "所有者: ";
    echo $perms_info['owner_read'] ? '读 ' : '';
    echo $perms_info['owner_write'] ? '写 ' : '';
    echo $perms_info['owner_execute'] ? '执行 ' : '';
    echo "<br>";

    echo "组: ";
    echo $perms_info['group_read'] ? '读 ' : '';
    echo $perms_info['group_write'] ? '写 ' : '';
    echo $perms_info['group_execute'] ? '执行 ' : '';
    echo "<br>";

    echo "其他用户: ";
    echo $perms_info['other_read'] ? '读 ' : '';
    echo $perms_info['other_write'] ? '写 ' : '';
    echo $perms_info['other_execute'] ? '执行 ' : '';
} else {
    echo $perms_info;
}
?>
示例3:检查文件权限是否安全
<?php
class FileSecurityChecker {

    public function checkFileSecurity($filename) {
        if (!file_exists($filename)) {
            return ['status' => 'error', 'message' => '文件不存在'];
        }

        $perms = fileperms($filename);
        $octal_perms = substr(sprintf('%o', $perms), -4);

        $issues = [];
        $security_level = 'secure';

        // 检查全局可写
        if (($perms & 0x0002) != 0) {
            $issues[] = '文件全局可写(其他用户可修改)';
            $security_level = 'danger';
        }

        // 检查全局可读(对于敏感文件)
        if (($perms & 0x0004) != 0) {
            $sensitive_extensions = ['pem', 'key', 'env', 'config', 'secret'];
            $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));

            if (in_array($extension, $sensitive_extensions)) {
                $issues[] = '敏感文件全局可读';
                $security_level = 'warning';
            }
        }

        // 检查setuid/setgid位
        if (($perms & 0x2000) != 0) {
            $issues[] = '设置了setuid位';
            $security_level = 'danger';
        }

        if (($perms & 0x1000) != 0) {
            $issues[] = '设置了setgid位';
            $security_level = 'danger';
        }

        // 检查粘滞位(对目录)
        if (is_dir($filename) && ($perms & 0x1000) == 0) {
            // 对于/tmp等目录,粘滞位是正常的
            if (strpos($filename, '/tmp') !== false || strpos($filename, '/var/tmp') !== false) {
                // 这是正常的
            } else {
                $issues[] = '目录没有设置粘滞位';
                $security_level = 'warning';
            }
        }

        // 检查文件所有者
        $uid = fileowner($filename);
        if ($uid === 0) {
            $issues[] = '文件由root所有';
            $security_level = 'warning';
        }

        return [
            'status' => 'success',
            'filename' => $filename,
            'permissions_octal' => $octal_perms,
            'permissions_symbolic' => $this->getSymbolicPermissions($perms),
            'security_level' => $security_level,
            'issues' => $issues,
            'issue_count' => count($issues),
            'recommendation' => $this->getRecommendation($issues)
        ];
    }

    public function checkDirectorySecurity($directory) {
        if (!is_dir($directory)) {
            return ['status' => 'error', 'message' => '目录不存在'];
        }

        $results = [
            'directory' => $directory,
            'total_files' => 0,
            'insecure_files' => 0,
            'files' => []
        ];

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isDot()) {
                continue;
            }

            if ($file->isFile()) {
                $filepath = $file->getPathname();
                $check_result = $this->checkFileSecurity($filepath);

                $results['total_files']++;

                if ($check_result['status'] === 'success') {
                    if ($check_result['security_level'] === 'danger' ||
                        $check_result['security_level'] === 'warning') {
                        $results['insecure_files']++;
                    }

                    $results['files'][] = $check_result;
                }
            }
        }

        return $results;
    }

    private function getSymbolicPermissions($perms) {
        $symbolic = '';
        $symbolic .= (($perms & 0x0100) ? 'r' : '-');
        $symbolic .= (($perms & 0x0080) ? 'w' : '-');
        $symbolic .= (($perms & 0x0040) ? 'x' : '-');
        $symbolic .= (($perms & 0x0020) ? 'r' : '-');
        $symbolic .= (($perms & 0x0010) ? 'w' : '-');
        $symbolic .= (($perms & 0x0008) ? 'x' : '-');
        $symbolic .= (($perms & 0x0004) ? 'r' : '-');
        $symbolic .= (($perms & 0x0002) ? 'w' : '-');
        $symbolic .= (($perms & 0x0001) ? 'x' : '-');
        return $symbolic;
    }

    private function getRecommendation($issues) {
        if (empty($issues)) {
            return '文件权限安全,无需操作';
        }

        $recommendations = [];

        foreach ($issues as $issue) {
            if (strpos($issue, '全局可写') !== false) {
                $recommendations[] = '使用 chmod o-w 命令移除其他用户的写权限';
            }

            if (strpos($issue, '敏感文件全局可读') !== false) {
                $recommendations[] = '使用 chmod o-r 命令移除其他用户的读权限';
            }

            if (strpos($issue, 'setuid') !== false || strpos($issue, 'setgid') !== false) {
                $recommendations[] = '检查文件是否需要setuid/setgid位,不需要则使用 chmod u-s,g-s 移除';
            }

            if (strpos($issue, 'root所有') !== false) {
                $recommendations[] = '考虑将文件所有者更改为非root用户';
            }
        }

        return array_unique($recommendations);
    }
}

// 使用示例
$checker = new FileSecurityChecker();

// 检查单个文件
$result = $checker->checkFileSecurity('/etc/shadow');

if ($result['status'] === 'success') {
    $security_icon = $result['security_level'] === 'secure' ? '✅' :
                    ($result['security_level'] === 'warning' ? '⚠️' : '❌');

    echo "{$security_icon} 文件: {$result['filename']}<br>";
    echo "权限: {$result['permissions_symbolic']} ({$result['permissions_octal']})<br>";
    echo "安全等级: {$result['security_level']}<br>";

    if ($result['issue_count'] > 0) {
        echo "发现问题:<br>";
        foreach ($result['issues'] as $issue) {
            echo "  • {$issue}<br>";
        }

        echo "建议:<br>";
        if (is_array($result['recommendation'])) {
            foreach ($result['recommendation'] as $rec) {
                echo "  • {$rec}<br>";
            }
        } else {
            echo "  • {$result['recommendation']}<br>";
        }
    }
}

// 检查目录
$dir_result = $checker->checkDirectorySecurity('/etc');
echo "<br>目录检查结果: {$dir_result['total_files']} 个文件,{$dir_result['insecure_files']} 个不安全文件";
?>
示例4:自动修复不安全的文件权限
<?php
class FilePermissionFixer {
    private $recommended_permissions = [
        'php' => 0644,
        'html' => 0644,
        'css' => 0644,
        'js' => 0644,
        'json' => 0644,
        'txt' => 0644,
        'md' => 0644,
        'yml' => 0644,
        'yaml' => 0644,
        'xml' => 0644,
        'ini' => 0644,
        'conf' => 0644,
        'sh' => 0755,
        'py' => 0755,
        'pl' => 0755,
        'jpg' => 0644,
        'png' => 0644,
        'gif' => 0644,
        'svg' => 0644,
        'directory' => 0755
    ];

    public function fixFilePermissions($filename) {
        if (!file_exists($filename)) {
            return ['status' => 'error', 'message' => '文件不存在'];
        }

        $current_perms = fileperms($filename);
        $current_octal = substr(sprintf('%o', $current_perms), -4);

        // 获取推荐权限
        $recommended_perms = $this->getRecommendedPermissions($filename);
        $recommended_octal = substr(sprintf('%o', $recommended_perms), -4);

        // 检查是否需要修复
        if (($current_perms & 0777) === $recommended_perms) {
            return [
                'status' => 'success',
                'filename' => $filename,
                'message' => '无需修复,权限正确',
                'current_perms' => $current_octal,
                'recommended_perms' => $recommended_octal
            ];
        }

        // 修复权限
        if (chmod($filename, $recommended_perms)) {
            return [
                'status' => 'success',
                'filename' => $filename,
                'message' => '权限修复成功',
                'old_perms' => $current_octal,
                'new_perms' => $recommended_octal,
                'changes' => $this->getPermissionChanges($current_perms, $recommended_perms)
            ];
        } else {
            return [
                'status' => 'error',
                'filename' => $filename,
                'message' => '权限修复失败',
                'current_perms' => $current_octal,
                'recommended_perms' => $recommended_octal
            ];
        }
    }

    public function fixDirectoryPermissions($directory, $recursive = true) {
        if (!is_dir($directory)) {
            return ['status' => 'error', 'message' => '目录不存在'];
        }

        $results = [
            'directory' => $directory,
            'total_files' => 0,
            'fixed_files' => 0,
            'failed_files' => 0,
            'unchanged_files' => 0,
            'details' => []
        ];

        $iterator = $recursive ?
            new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) :
            new DirectoryIterator($directory);

        foreach ($iterator as $file) {
            if ($file->isDot()) {
                continue;
            }

            $filepath = $file->getPathname();
            $results['total_files']++;

            $fix_result = $this->fixFilePermissions($filepath);

            if ($fix_result['status'] === 'success') {
                if (isset($fix_result['old_perms'])) {
                    $results['fixed_files']++;
                } else {
                    $results['unchanged_files']++;
                }
            } else {
                $results['failed_files']++;
            }

            $results['details'][] = $fix_result;
        }

        return $results;
    }

    private function getRecommendedPermissions($filename) {
        if (is_dir($filename)) {
            return $this->recommended_permissions['directory'];
        }

        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));

        if (isset($this->recommended_permissions[$extension])) {
            return $this->recommended_permissions[$extension];
        }

        // 默认权限
        return 0644;
    }

    private function getPermissionChanges($old_perms, $new_perms) {
        $changes = [];

        $old_owner = (($old_perms & 0x0100) ? 'r' : '-') .
                    (($old_perms & 0x0080) ? 'w' : '-') .
                    (($old_perms & 0x0040) ? 'x' : '-');

        $new_owner = (($new_perms & 0x0100) ? 'r' : '-') .
                    (($new_perms & 0x0080) ? 'w' : '-') .
                    (($new_perms & 0x0040) ? 'x' : '-');

        if ($old_owner !== $new_owner) {
            $changes[] = "所有者权限: {$old_owner} → {$new_owner}";
        }

        $old_group = (($old_perms & 0x0020) ? 'r' : '-') .
                    (($old_perms & 0x0010) ? 'w' : '-') .
                    (($old_perms & 0x0008) ? 'x' : '-');

        $new_group = (($new_perms & 0x0020) ? 'r' : '-') .
                    (($new_perms & 0x0010) ? 'w' : '-') .
                    (($new_perms & 0x0008) ? 'x' : '-');

        if ($old_group !== $new_group) {
            $changes[] = "组权限: {$old_group} → {$new_group}";
        }

        $old_other = (($old_perms & 0x0004) ? 'r' : '-') .
                    (($old_perms & 0x0002) ? 'w' : '-') .
                    (($old_perms & 0x0001) ? 'x' : '-');

        $new_other = (($new_perms & 0x0004) ? 'r' : '-') .
                    (($new_perms & 0x0002) ? 'w' : '-') .
                    (($new_perms & 0x0001) ? 'x' : '-');

        if ($old_other !== $new_other) {
            $changes[] = "其他用户权限: {$old_other} → {$new_other}";
        }

        return $changes;
    }
}

// 使用示例
$fixer = new FilePermissionFixer();

// 修复单个文件
$result = $fixer->fixFilePermissions('config.php');
if ($result['status'] === 'success') {
    echo "✅ {$result['message']}<br>";
    if (isset($result['old_perms'])) {
        echo "权限从 {$result['old_perms']} 改为 {$result['new_perms']}<br>";
        if (!empty($result['changes'])) {
            echo "变更详情:<br>";
            foreach ($result['changes'] as $change) {
                echo "  • {$change}<br>";
            }
        }
    }
} else {
    echo "❌ {$result['message']}<br>";
}

// 修复整个目录
$dir_result = $fixer->fixDirectoryPermissions('/var/www/html', true);
echo "<br>目录修复结果:<br>";
echo "总文件数: {$dir_result['total_files']}<br>";
echo "修复文件数: {$dir_result['fixed_files']}<br>";
echo "未变化文件数: {$dir_result['unchanged_files']}<br>";
echo "失败文件数: {$dir_result['failed_files']}<br>";
?>
示例5:权限可视化工具
<?php
class PermissionVisualizer {

    public function visualizeFilePermissions($filename) {
        if (!file_exists($filename)) {
            return ['status' => 'error', 'message' => '文件不存在'];
        }

        $perms = fileperms($filename);
        $uid = fileowner($filename);
        $gid = filegroup($filename);

        // 获取用户和组信息
        $user_info = $this->getUserInfo($uid);
        $group_info = $this->getGroupInfo($gid);

        // 解析权限
        $permission_data = $this->parsePermissions($perms);

        return [
            'status' => 'success',
            'filename' => $filename,
            'permissions' => $permission_data,
            'owner' => [
                'id' => $uid,
                'name' => $user_info['name']
            ],
            'group' => [
                'id' => $gid,
                'name' => $group_info['name']
            ],
            'visualization' => $this->createVisualization($permission_data)
        ];
    }

    private function parsePermissions($perms) {
        // 文件类型
        $type = '';
        $type_description = '';

        switch ($perms & 0xF000) {
            case 0xC000:
                $type = 's';
                $type_description = '套接字 (socket)';
                break;
            case 0xA000:
                $type = 'l';
                $type_description = '符号链接 (symbolic link)';
                break;
            case 0x8000:
                $type = '-';
                $type_description = '普通文件 (regular file)';
                break;
            case 0x6000:
                $type = 'b';
                $type_description = '块设备 (block device)';
                break;
            case 0x4000:
                $type = 'd';
                $type_description = '目录 (directory)';
                break;
            case 0x2000:
                $type = 'c';
                $type_description = '字符设备 (character device)';
                break;
            case 0x1000:
                $type = 'p';
                $type_description = '管道 (pipe)';
                break;
            default:
                $type = 'u';
                $type_description = '未知 (unknown)';
        }

        // 特殊权限位
        $setuid = ($perms & 0x0800) != 0;
        $setgid = ($perms & 0x0400) != 0;
        $sticky = ($perms & 0x0200) != 0;

        return [
            'type' => $type,
            'type_description' => $type_description,
            'octal_full' => sprintf("%o", $perms),
            'octal_short' => substr(sprintf('%o', $perms), -4),
            'symbolic' => $this->getSymbolicPermissions($perms),
            'special_bits' => [
                'setuid' => $setuid,
                'setgid' => $setgid,
                'sticky' => $sticky
            ],
            'owner_perms' => [
                'read' => ($perms & 0x0100) != 0,
                'write' => ($perms & 0x0080) != 0,
                'execute' => ($perms & 0x0040) != 0,
                'execute_special' => $setuid
            ],
            'group_perms' => [
                'read' => ($perms & 0x0020) != 0,
                'write' => ($perms & 0x0010) != 0,
                'execute' => ($perms & 0x0008) != 0,
                'execute_special' => $setgid
            ],
            'other_perms' => [
                'read' => ($perms & 0x0004) != 0,
                'write' => ($perms & 0x0002) != 0,
                'execute' => ($perms & 0x0001) != 0,
                'execute_special' => $sticky
            ]
        ];
    }

    private function getUserInfo($uid) {
        if (function_exists('posix_getpwuid')) {
            $info = posix_getpwuid($uid);
            if ($info) {
                return ['name' => $info['name'], 'uid' => $uid];
            }
        }
        return ['name' => "uid:{$uid}", 'uid' => $uid];
    }

    private function getGroupInfo($gid) {
        if (function_exists('posix_getgrgid')) {
            $info = posix_getgrgid($gid);
            if ($info) {
                return ['name' => $info['name'], 'gid' => $gid];
            }
        }
        return ['name' => "gid:{$gid}", 'gid' => $gid];
    }

    private function getSymbolicPermissions($perms) {
        $symbolic = '';
        $symbolic .= (($perms & 0x0100) ? 'r' : '-');
        $symbolic .= (($perms & 0x0080) ? 'w' : '-');
        $symbolic .= (($perms & 0x0040) ?
                    (($perms & 0x0800) ? 's' : 'x') :
                    (($perms & 0x0800) ? 'S' : '-'));
        $symbolic .= (($perms & 0x0020) ? 'r' : '-');
        $symbolic .= (($perms & 0x0010) ? 'w' : '-');
        $symbolic .= (($perms & 0x0008) ?
                    (($perms & 0x0400) ? 's' : 'x') :
                    (($perms & 0x0400) ? 'S' : '-'));
        $symbolic .= (($perms & 0x0004) ? 'r' : '-');
        $symbolic .= (($perms & 0x0002) ? 'w' : '-');
        $symbolic .= (($perms & 0x0001) ?
                    (($perms & 0x0200) ? 't' : 'x') :
                    (($perms & 0x0200) ? 'T' : '-'));
        return $symbolic;
    }

    private function createVisualization($permission_data) {
        $html = '<div class="permission-visualization">';

        // 文件类型
        $html .= '<div class="permission-type">';
        $html .= '<strong>文件类型:</strong> ' . $permission_data['type_description'];
        $html .= '</div>';

        // 权限矩阵
        $html .= '<table class="permission-matrix">';
        $html .= '<tr><th>权限组</th><th>读</th><th>写</th><th>执行</th><th>特殊</th></tr>';

        // 所有者权限
        $html .= '<tr>';
        $html .= '<td>所有者</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['owner_perms']['read'], 'r') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['owner_perms']['write'], 'w') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['owner_perms']['execute'], 'x') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['owner_perms']['execute_special'], 's', 'setuid') . '</td>';
        $html .= '</tr>';

        // 组权限
        $html .= '<tr>';
        $html .= '<td>组</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['group_perms']['read'], 'r') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['group_perms']['write'], 'w') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['group_perms']['execute'], 'x') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['group_perms']['execute_special'], 's', 'setgid') . '</td>';
        $html .= '</tr>';

        // 其他用户权限
        $html .= '<tr>';
        $html .= '<td>其他用户</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['other_perms']['read'], 'r') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['other_perms']['write'], 'w') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['other_perms']['execute'], 'x') . '</td>';
        $html .= '<td>' . $this->getPermissionCell($permission_data['other_perms']['execute_special'], 't', 'sticky') . '</td>';
        $html .= '</tr>';

        $html .= '</table>';

        // 权限摘要
        $html .= '<div class="permission-summary">';
        $html .= '<strong>权限摘要:</strong> ';
        $html .= '符号表示: <code>' . $permission_data['symbolic'] . '</code> | ';
        $html .= '八进制表示: <code>' . $permission_data['octal_short'] . '</code>';
        $html .= '</div>';

        $html .= '</div>';

        return $html;
    }

    private function getPermissionCell($has_permission, $symbol, $special = '') {
        if ($has_permission) {
            $class = 'permission-granted';
            $title = '已授权';
            if ($special) {
                $title = $special . ' 位已设置';
            }
            return '<span class="' . $class . '" title="' . $title . '">' . $symbol . '</span>';
        } else {
            $class = 'permission-denied';
            $title = '未授权';
            return '<span class="' . $class . '" title="' . $title . '">-</span>';
        }
    }
}

// 使用示例
$visualizer = new PermissionVisualizer();
$result = $visualizer->visualizeFilePermissions('/usr/bin/passwd');

if ($result['status'] === 'success') {
    echo "<h4>文件权限可视化: {$result['filename']}</h4>";
    echo "所有者: {$result['owner']['name']} (UID: {$result['owner']['id']})<br>";
    echo "组: {$result['group']['name']} (GID: {$result['group']['id']})<br>";

    echo $result['visualization'];
}
?>

与类似函数的比较

函数 描述 返回内容 适用场景
fileperms() 获取文件权限 权限位掩码(整数) 检查文件访问权限
fileowner() 获取文件所有者ID 用户ID(整数) 检查文件所有者
filegroup() 获取文件组ID 组ID(整数) 检查文件所属组
is_readable() 检查文件是否可读 布尔值 检查当前用户是否有读权限
is_writable() 检查文件是否可写 布尔值 检查当前用户是否有写权限
is_executable() 检查文件是否可执行 布尔值 检查当前用户是否有执行权限

权限位详解

Unix文件权限基础知识
权限位 八进制值 符号 描述
所有者读 0400 r-- 文件所有者可以读取文件
所有者写 0200 -w- 文件所有者可以写入文件
所有者执行 0100 --x 文件所有者可以执行文件
组读 0040 r-- 文件所属组可以读取文件
组写 0020 -w- 文件所属组可以写入文件
组执行 0010 --x 文件所属组可以执行文件
其他读 0004 r-- 其他用户可以读取文件
其他写 0002 -w- 其他用户可以写入文件
其他执行 0001 --x 其他用户可以执行文件
setuid 04000 s 以文件所有者身份执行
setgid 02000 s 以文件所属组身份执行
粘滞位 01000 t 只有所有者可以删除/重命名

常见权限值示例

0755

rwxr-xr-x
所有者:读、写、执行
组:读、执行
其他:读、执行

常用于目录和可执行文件
0644

rw-r--r--
所有者:读、写
组:读
其他:读

常用于普通文件
0777

rwxrwxrwx
所有人:读、写、执行

安全风险!避免使用

安全最佳实践

安全建议
  • Web服务器文件不应设置为全局可写(避免0777、0666)
  • 配置文件应限制为所有者可读写,组可读(0640)
  • 上传目录应设置为不可执行(避免0755,使用0750或0730)
  • 敏感文件(如私钥)应设置为仅所有者可读(0600)
  • 定期审计文件权限,使用fileperms()进行检查
  • 使用最小权限原则,只授予必要的权限
完整示例:综合权限管理工具
<?php
class ComprehensivePermissionManager {

    public function analyzeFile($filename) {
        if (!file_exists($filename)) {
            return ['status' => 'error', 'message' => '文件不存在'];
        }

        // 获取所有文件信息
        $perms = fileperms($filename);
        $uid = fileowner($filename);
        $gid = filegroup($filename);
        $size = filesize($filename);
        $mtime = filemtime($filename);

        // 解析权限
        $permission_info = $this->parsePermissions($perms);

        // 检查安全问题
        $security_issues = $this->checkSecurityIssues($filename, $perms, $uid, $gid);

        // 获取推荐权限
        $recommended_perms = $this->getRecommendedPermissions($filename);

        return [
            'status' => 'success',
            'filename' => $filename,
            'file_type' => is_dir($filename) ? 'directory' : 'file',
            'size' => $size,
            'modified' => date('Y-m-d H:i:s', $mtime),
            'owner' => $this->getUserInfo($uid),
            'group' => $this->getGroupInfo($gid),
            'permissions' => $permission_info,
            'security' => [
                'level' => empty($security_issues) ? 'secure' : (count($security_issues) > 2 ? 'danger' : 'warning'),
                'issues' => $security_issues,
                'issue_count' => count($security_issues)
            ],
            'recommendations' => [
                'permissions' => $recommended_perms,
                'actions' => $this->getRecommendedActions($security_issues, $perms, $recommended_perms)
            ]
        ];
    }

    private function parsePermissions($perms) {
        $symbolic = '';
        $symbolic .= (($perms & 0x0100) ? 'r' : '-');
        $symbolic .= (($perms & 0x0080) ? 'w' : '-');
        $symbolic .= (($perms & 0x0040) ? 'x' : '-');
        $symbolic .= (($perms & 0x0020) ? 'r' : '-');
        $symbolic .= (($perms & 0x0010) ? 'w' : '-');
        $symbolic .= (($perms & 0x0008) ? 'x' : '-');
        $symbolic .= (($perms & 0x0004) ? 'r' : '-');
        $symbolic .= (($perms & 0x0002) ? 'w' : '-');
        $symbolic .= (($perms & 0x0001) ? 'x' : '-');

        return [
            'decimal' => $perms,
            'octal_full' => sprintf("%o", $perms),
            'octal_short' => substr(sprintf('%o', $perms), -4),
            'symbolic' => $symbolic,
            'owner_read' => ($perms & 0x0100) != 0,
            'owner_write' => ($perms & 0x0080) != 0,
            'owner_execute' => ($perms & 0x0040) != 0,
            'group_read' => ($perms & 0x0020) != 0,
            'group_write' => ($perms & 0x0010) != 0,
            'group_execute' => ($perms & 0x0008) != 0,
            'other_read' => ($perms & 0x0004) != 0,
            'other_write' => ($perms & 0x0002) != 0,
            'other_execute' => ($perms & 0x0001) != 0
        ];
    }

    private function checkSecurityIssues($filename, $perms, $uid, $gid) {
        $issues = [];

        // 检查全局可写
        if (($perms & 0x0002) != 0) {
            $issues[] = '其他用户可写(安全风险)';
        }

        // 检查全局可读(对于敏感文件)
        $sensitive_patterns = ['/.pem$/', '/.key$/', '/.env$/', '/config\./', '/secret/'];
        foreach ($sensitive_patterns as $pattern) {
            if (preg_match($pattern, $filename)) {
                if (($perms & 0x0004) != 0) {
                    $issues[] = '敏感文件其他用户可读';
                }
                break;
            }
        }

        // 检查权限是否过宽
        $octal_perms = $perms & 0777;
        if ($octal_perms === 0777) {
            $issues[] = '权限过宽(0777)';
        } elseif ($octal_perms === 0666) {
            $issues[] = '权限过宽(0666)';
        }

        // 检查所有者
        if ($uid === 0) {
            $issues[] = '文件由root所有(可能不安全)';
        }

        // 检查PHP文件是否有执行权限
        if (pathinfo($filename, PATHINFO_EXTENSION) === 'php' && ($perms & 0x0040) != 0) {
            $issues[] = 'PHP文件所有者有执行权限(通常不需要)';
        }

        return $issues;
    }

    private function getRecommendedPermissions($filename) {
        if (is_dir($filename)) {
            return 0755;
        }

        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));

        $recommendations = [
            'php' => 0644,
            'html' => 0644,
            'css' => 0644,
            'js' => 0644,
            'json' => 0644,
            'txt' => 0644,
            'md' => 0644,
            'yml' => 0640,
            'yaml' => 0640,
            'xml' => 0644,
            'ini' => 0640,
            'conf' => 0640,
            'pem' => 0600,
            'key' => 0600,
            'env' => 0600,
            'sh' => 0755,
            'py' => 0755,
            'pl' => 0755,
            'jpg' => 0644,
            'png' => 0644,
            'gif' => 0644,
            'svg' => 0644
        ];

        return $recommendations[$extension] ?? 0644;
    }

    private function getRecommendedActions($issues, $current_perms, $recommended_perms) {
        $actions = [];

        if (empty($issues)) {
            return ['无需操作,权限安全'];
        }

        foreach ($issues as $issue) {
            if (strpos($issue, '其他用户可写') !== false) {
                $actions[] = '移除其他用户写权限: chmod o-w [文件]';
            }

            if (strpos($issue, '敏感文件其他用户可读') !== false) {
                $actions[] = '移除其他用户读权限: chmod o-r [文件]';
            }

            if (strpos($issue, '权限过宽') !== false) {
                $actions[] = '调整权限: chmod ' . substr(sprintf('%o', $recommended_perms), -4) . ' [文件]';
            }

            if (strpos($issue, 'root所有') !== false) {
                $actions[] = '更改所有者: chown www-data [文件]';
            }

            if (strpos($issue, 'PHP文件所有者有执行权限') !== false) {
                $actions[] = '移除执行权限: chmod u-x [文件]';
            }
        }

        return array_unique($actions);
    }

    private function getUserInfo($uid) {
        if (function_exists('posix_getpwuid')) {
            $info = posix_getpwuid($uid);
            if ($info) {
                return ['id' => $uid, 'name' => $info['name']];
            }
        }
        return ['id' => $uid, 'name' => "uid:{$uid}"];
    }

    private function getGroupInfo($gid) {
        if (function_exists('posix_getgrgid')) {
            $info = posix_getgrgid($gid);
            if ($info) {
                return ['id' => $gid, 'name' => $info['name']];
            }
        }
        return ['id' => $gid, 'name' => "gid:{$gid}"];
    }
}

// 使用示例
$manager = new ComprehensivePermissionManager();
$analysis = $manager->analyzeFile('/etc/passwd');

if ($analysis['status'] === 'success') {
    echo "<h4>文件权限综合分析: {$analysis['filename']}</h4>";

    echo "<div class='row'>";
    echo "<div class='col-md-6'>";
    echo "<h5>基本信息</h5>";
    echo "文件类型: {$analysis['file_type']}<br>";
    echo "文件大小: " . number_format($analysis['size']) . " 字节<br>";
    echo "最后修改: {$analysis['modified']}<br>";
    echo "所有者: {$analysis['owner']['name']} (UID: {$analysis['owner']['id']})<br>";
    echo "组: {$analysis['group']['name']} (GID: {$analysis['group']['id']})<br>";
    echo "</div>";

    echo "<div class='col-md-6'>";
    echo "<h5>权限信息</h5>";
    echo "符号表示: {$analysis['permissions']['symbolic']}<br>";
    echo "八进制表示: {$analysis['permissions']['octal_short']}<br>";
    echo "完整八进制: {$analysis['permissions']['octal_full']}<br>";
    echo "十进制: {$analysis['permissions']['decimal']}<br>";
    echo "</div>";
    echo "</div>";

    echo "<h5>安全分析</h5>";
    $security_level = $analysis['security']['level'];
    $security_class = $security_level === 'secure' ? 'success' :
                     ($security_level === 'warning' ? 'warning' : 'danger');

    echo "<div class='alert alert-{$security_class}'>";
    echo "安全等级: {$security_level}<br>";
    echo "发现问题: {$analysis['security']['issue_count']} 个<br>";

    if ($analysis['security']['issue_count'] > 0) {
        echo "问题列表:<br>";
        foreach ($analysis['security']['issues'] as $issue) {
            echo "  • {$issue}<br>";
        }
    }
    echo "</div>";

    if (!empty($analysis['recommendations']['actions'])) {
        echo "<h5>建议操作</h5>";
        echo "<ul>";
        foreach ($analysis['recommendations']['actions'] as $action) {
            echo "<li>{$action}</li>";
        }
        echo "</ul>";
    }
}
?>