[PHP]posix_uname関数とは?システム情報取得を徹底解説

PHP

こんにちは!今回はPHPのPOSIX拡張モジュールに含まれる「posix_uname」関数について、詳しく解説していきます。この関数は、実行中のシステムに関する詳細な情報を取得できる非常に便利なツールです。

posix_unameとは何か?

posix_unameは、現在のシステムに関する情報(OS名、ホスト名、カーネルバージョンなど)を取得する関数です。UNIXコマンドのunameと同等の情報をPHPから取得できます。

基本的な構文

posix_uname(): array|false

パラメータ:

  • なし

戻り値:

  • 成功時: システム情報を含む連想配列
  • 失敗時: false

返される配列の構造

<?php
$uname = posix_uname();

/*
返される配列:
[
    'sysname'  => システム名(例: 'Linux', 'Darwin'),
    'nodename' => ネットワーク上のホスト名,
    'release'  => OSリリースバージョン,
    'version'  => OSバージョン情報,
    'machine'  => ハードウェアタイプ(例: 'x86_64', 'arm64')
]
*/

print_r($uname);

/*
出力例(Linux):
Array
(
    [sysname] => Linux
    [nodename] => server01
    [release] => 5.15.0-56-generic
    [version] => #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022
    [machine] => x86_64
)

出力例(macOS):
Array
(
    [sysname] => Darwin
    [nodename] => MacBook-Pro.local
    [release] => 22.1.0
    [version] => Darwin Kernel Version 22.1.0
    [machine] => arm64
)
*/
?>

基本的な使用例

例1: システム情報の表示

<?php
$info = posix_uname();

if ($info === false) {
    die("システム情報を取得できませんでした\n");
}

echo "=== システム情報 ===\n";
echo "OS名: {$info['sysname']}\n";
echo "ホスト名: {$info['nodename']}\n";
echo "カーネルリリース: {$info['release']}\n";
echo "カーネルバージョン: {$info['version']}\n";
echo "マシンタイプ: {$info['machine']}\n";
?>

例2: OS判定

<?php
function detectOS() {
    $uname = posix_uname();
    
    if (!$uname) {
        return 'Unknown';
    }
    
    $sysname = strtolower($uname['sysname']);
    
    switch ($sysname) {
        case 'linux':
            return 'Linux';
        case 'darwin':
            return 'macOS';
        case 'freebsd':
            return 'FreeBSD';
        case 'openbsd':
            return 'OpenBSD';
        case 'sunos':
            return 'Solaris';
        default:
            return ucfirst($sysname);
    }
}

// 使用例
$os = detectOS();
echo "検出されたOS: {$os}\n";

// OS別の処理
switch ($os) {
    case 'Linux':
        echo "Linuxコマンドを実行します\n";
        break;
    case 'macOS':
        echo "macOSコマンドを実行します\n";
        break;
    default:
        echo "その他のOSです\n";
}
?>

例3: アーキテクチャの判定

<?php
function getArchitecture() {
    $uname = posix_uname();
    
    if (!$uname) {
        return 'Unknown';
    }
    
    $machine = $uname['machine'];
    
    // 64ビット判定
    if (preg_match('/x86[_-]?64|amd64|x64/i', $machine)) {
        return 'x86_64';
    }
    
    // ARM判定
    if (preg_match('/arm64|aarch64/i', $machine)) {
        return 'ARM64';
    }
    
    if (preg_match('/arm/i', $machine)) {
        return 'ARM32';
    }
    
    // 32ビットx86
    if (preg_match('/i[3-6]86/i', $machine)) {
        return 'x86';
    }
    
    return $machine;
}

$arch = getArchitecture();
echo "アーキテクチャ: {$arch}\n";

// ビット数の判定
$is64bit = in_array($arch, ['x86_64', 'ARM64']);
echo "64ビット環境: " . ($is64bit ? 'はい' : 'いいえ') . "\n";
?>

実践的な使用例

例1: システム互換性チェッカー

<?php
class SystemCompatibility {
    private $requirements;
    private $systemInfo;
    
    public function __construct(array $requirements) {
        $this->requirements = $requirements;
        $this->systemInfo = posix_uname();
    }
    
    public function check() {
        if (!$this->systemInfo) {
            return [
                'compatible' => false,
                'reason' => 'システム情報を取得できませんでした'
            ];
        }
        
        $checks = [
            'os' => $this->checkOS(),
            'architecture' => $this->checkArchitecture(),
            'kernel' => $this->checkKernelVersion()
        ];
        
        $compatible = true;
        $reasons = [];
        
        foreach ($checks as $check => $result) {
            if (!$result['passed']) {
                $compatible = false;
                $reasons[] = $result['reason'];
            }
        }
        
        return [
            'compatible' => $compatible,
            'reasons' => $reasons,
            'checks' => $checks,
            'system_info' => $this->systemInfo
        ];
    }
    
    private function checkOS() {
        if (!isset($this->requirements['os'])) {
            return ['passed' => true];
        }
        
        $allowedOS = (array)$this->requirements['os'];
        $currentOS = strtolower($this->systemInfo['sysname']);
        
        $passed = false;
        foreach ($allowedOS as $os) {
            if (strtolower($os) === $currentOS) {
                $passed = true;
                break;
            }
        }
        
        return [
            'passed' => $passed,
            'reason' => $passed ? '' : "OS {$this->systemInfo['sysname']} はサポートされていません(対応OS: " . implode(', ', $allowedOS) . ")",
            'current' => $this->systemInfo['sysname'],
            'required' => $allowedOS
        ];
    }
    
    private function checkArchitecture() {
        if (!isset($this->requirements['architecture'])) {
            return ['passed' => true];
        }
        
        $allowedArch = (array)$this->requirements['architecture'];
        $currentArch = $this->systemInfo['machine'];
        
        $passed = false;
        foreach ($allowedArch as $arch) {
            if (preg_match("/{$arch}/i", $currentArch)) {
                $passed = true;
                break;
            }
        }
        
        return [
            'passed' => $passed,
            'reason' => $passed ? '' : "アーキテクチャ {$currentArch} はサポートされていません(対応: " . implode(', ', $allowedArch) . ")",
            'current' => $currentArch,
            'required' => $allowedArch
        ];
    }
    
    private function checkKernelVersion() {
        if (!isset($this->requirements['min_kernel_version'])) {
            return ['passed' => true];
        }
        
        $minVersion = $this->requirements['min_kernel_version'];
        $currentVersion = $this->systemInfo['release'];
        
        // バージョン番号を抽出(例: "5.15.0-56-generic" -> "5.15.0")
        preg_match('/^(\d+\.\d+\.\d+)/', $currentVersion, $matches);
        $current = $matches[1] ?? '0.0.0';
        
        $passed = version_compare($current, $minVersion, '>=');
        
        return [
            'passed' => $passed,
            'reason' => $passed ? '' : "カーネルバージョン {$current} が要件(>= {$minVersion})を満たしていません",
            'current' => $current,
            'required' => ">= {$minVersion}"
        ];
    }
    
    public function printReport() {
        $result = $this->check();
        
        echo "=== システム互換性チェック ===\n\n";
        
        echo "【現在のシステム】\n";
        echo "  OS: {$this->systemInfo['sysname']}\n";
        echo "  ホスト名: {$this->systemInfo['nodename']}\n";
        echo "  カーネル: {$this->systemInfo['release']}\n";
        echo "  アーキテクチャ: {$this->systemInfo['machine']}\n\n";
        
        echo "【互換性チェック結果】\n";
        
        foreach ($result['checks'] as $check => $details) {
            $status = $details['passed'] ? '✓ OK' : '✗ NG';
            echo "  {$check}: {$status}\n";
            
            if (!$details['passed'] && isset($details['reason'])) {
                echo "    理由: {$details['reason']}\n";
            }
        }
        
        echo "\n【総合判定】\n";
        if ($result['compatible']) {
            echo "  ✓ このシステムは要件を満たしています\n";
        } else {
            echo "  ✗ このシステムは要件を満たしていません\n";
            echo "\n【問題点】\n";
            foreach ($result['reasons'] as $reason) {
                echo "  - {$reason}\n";
            }
        }
    }
}

// 使用例
$requirements = [
    'os' => ['Linux', 'Darwin'],
    'architecture' => ['x86_64', 'arm64'],
    'min_kernel_version' => '5.0.0'
];

$checker = new SystemCompatibility($requirements);
$checker->printReport();
?>

例2: システム情報レポーター

<?php
class SystemReporter {
    private $uname;
    
    public function __construct() {
        $this->uname = posix_uname();
    }
    
    public function generateReport() {
        $report = [
            'basic' => $this->getBasicInfo(),
            'distribution' => $this->getDistributionInfo(),
            'hardware' => $this->getHardwareInfo(),
            'php' => $this->getPhpInfo(),
            'environment' => $this->getEnvironmentInfo()
        ];
        
        return $report;
    }
    
    private function getBasicInfo() {
        if (!$this->uname) {
            return ['error' => 'システム情報を取得できません'];
        }
        
        return [
            'os' => $this->uname['sysname'],
            'hostname' => $this->uname['nodename'],
            'kernel_release' => $this->uname['release'],
            'kernel_version' => $this->uname['version'],
            'architecture' => $this->uname['machine']
        ];
    }
    
    private function getDistributionInfo() {
        $os = strtolower($this->uname['sysname']);
        
        if ($os !== 'linux') {
            return ['type' => $os];
        }
        
        // Linuxディストリビューション情報を取得
        $distro = [];
        
        // /etc/os-releaseから読み取り
        if (file_exists('/etc/os-release')) {
            $lines = file('/etc/os-release', FILE_IGNORE_NEW_LINES);
            foreach ($lines as $line) {
                if (strpos($line, '=') !== false) {
                    list($key, $value) = explode('=', $line, 2);
                    $distro[$key] = trim($value, '"');
                }
            }
        }
        
        return [
            'type' => 'Linux',
            'name' => $distro['NAME'] ?? 'Unknown',
            'version' => $distro['VERSION'] ?? 'Unknown',
            'id' => $distro['ID'] ?? 'Unknown'
        ];
    }
    
    private function getHardwareInfo() {
        $info = [
            'architecture' => $this->uname['machine'],
            'processor_count' => 1
        ];
        
        // CPUコア数を取得
        if (file_exists('/proc/cpuinfo')) {
            $cpuinfo = file_get_contents('/proc/cpuinfo');
            preg_match_all('/^processor/m', $cpuinfo, $matches);
            $info['processor_count'] = count($matches[0]);
        }
        
        // メモリ情報
        if (file_exists('/proc/meminfo')) {
            $meminfo = file_get_contents('/proc/meminfo');
            if (preg_match('/MemTotal:\s+(\d+)/', $meminfo, $matches)) {
                $info['memory_total_mb'] = round($matches[1] / 1024);
            }
        }
        
        return $info;
    }
    
    private function getPhpInfo() {
        return [
            'version' => PHP_VERSION,
            'sapi' => PHP_SAPI,
            'os' => PHP_OS,
            'architecture' => PHP_INT_SIZE * 8 . '-bit',
            'extensions' => get_loaded_extensions()
        ];
    }
    
    private function getEnvironmentInfo() {
        return [
            'user' => posix_getpwuid(posix_getuid())['name'] ?? 'unknown',
            'cwd' => getcwd(),
            'home' => getenv('HOME') ?: 'N/A',
            'shell' => getenv('SHELL') ?: 'N/A',
            'path' => getenv('PATH') ?: 'N/A'
        ];
    }
    
    public function printReport() {
        $report = $this->generateReport();
        
        echo "=== システムレポート ===\n\n";
        
        echo "【基本情報】\n";
        foreach ($report['basic'] as $key => $value) {
            echo "  " . ucfirst(str_replace('_', ' ', $key)) . ": {$value}\n";
        }
        
        echo "\n【ディストリビューション】\n";
        foreach ($report['distribution'] as $key => $value) {
            echo "  " . ucfirst($key) . ": {$value}\n";
        }
        
        echo "\n【ハードウェア】\n";
        foreach ($report['hardware'] as $key => $value) {
            if ($key !== 'processor_count') {
                echo "  " . ucfirst(str_replace('_', ' ', $key)) . ": {$value}\n";
            } else {
                echo "  CPU コア数: {$value}\n";
            }
        }
        
        echo "\n【PHP情報】\n";
        echo "  Version: {$report['php']['version']}\n";
        echo "  SAPI: {$report['php']['sapi']}\n";
        echo "  OS: {$report['php']['os']}\n";
        echo "  Architecture: {$report['php']['architecture']}\n";
        echo "  Loaded extensions: " . count($report['php']['extensions']) . "\n";
        
        echo "\n【環境情報】\n";
        foreach ($report['environment'] as $key => $value) {
            echo "  " . ucfirst($key) . ": {$value}\n";
        }
    }
    
    public function exportToJson($filename) {
        $report = $this->generateReport();
        file_put_contents($filename, json_encode($report, JSON_PRETTY_PRINT));
        echo "レポートを {$filename} にエクスポートしました\n";
    }
    
    public function exportToHtml($filename) {
        $report = $this->generateReport();
        
        $html = "<!DOCTYPE html>\n<html>\n<head>\n";
        $html .= "<meta charset='UTF-8'>\n";
        $html .= "<title>システムレポート - {$report['basic']['hostname']}</title>\n";
        $html .= "<style>\n";
        $html .= "body { font-family: Arial, sans-serif; margin: 20px; }\n";
        $html .= "h2 { color: #333; border-bottom: 2px solid #4CAF50; }\n";
        $html .= "table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }\n";
        $html .= "th, td { text-align: left; padding: 8px; border: 1px solid #ddd; }\n";
        $html .= "th { background-color: #4CAF50; color: white; }\n";
        $html .= "</style>\n</head>\n<body>\n";
        
        $html .= "<h1>システムレポート</h1>\n";
        $html .= "<p>生成日時: " . date('Y-m-d H:i:s') . "</p>\n";
        
        foreach ($report as $section => $data) {
            $html .= "<h2>" . ucfirst($section) . "</h2>\n";
            $html .= "<table>\n";
            
            foreach ($data as $key => $value) {
                if (is_array($value)) {
                    $value = implode(', ', array_slice($value, 0, 10)) . 
                             (count($value) > 10 ? '...' : '');
                }
                $html .= "<tr><th>" . htmlspecialchars($key) . "</th>";
                $html .= "<td>" . htmlspecialchars($value) . "</td></tr>\n";
            }
            
            $html .= "</table>\n";
        }
        
        $html .= "</body>\n</html>";
        
        file_put_contents($filename, $html);
        echo "HTMLレポートを {$filename} にエクスポートしました\n";
    }
}

// 使用例
$reporter = new SystemReporter();

// コンソールに表示
$reporter->printReport();

// JSONにエクスポート
echo "\n";
$reporter->exportToJson('/tmp/system_report.json');

// HTMLにエクスポート
$reporter->exportToHtml('/tmp/system_report.html');
?>

例3: プラットフォーム固有のパス処理

<?php
class PlatformPaths {
    private $platform;
    private $uname;
    
    public function __construct() {
        $this->uname = posix_uname();
        $this->platform = strtolower($this->uname['sysname']);
    }
    
    public function getTempDir() {
        switch ($this->platform) {
            case 'linux':
            case 'freebsd':
            case 'openbsd':
                return '/tmp';
            case 'darwin':
                return getenv('TMPDIR') ?: '/tmp';
            default:
                return sys_get_temp_dir();
        }
    }
    
    public function getConfigDir() {
        $home = getenv('HOME');
        
        switch ($this->platform) {
            case 'linux':
            case 'freebsd':
            case 'openbsd':
                $xdgConfig = getenv('XDG_CONFIG_HOME');
                return $xdgConfig ?: ($home . '/.config');
            case 'darwin':
                return $home . '/Library/Application Support';
            default:
                return $home;
        }
    }
    
    public function getDataDir() {
        $home = getenv('HOME');
        
        switch ($this->platform) {
            case 'linux':
            case 'freebsd':
            case 'openbsd':
                $xdgData = getenv('XDG_DATA_HOME');
                return $xdgData ?: ($home . '/.local/share');
            case 'darwin':
                return $home . '/Library/Application Support';
            default:
                return $home;
        }
    }
    
    public function getCacheDir() {
        $home = getenv('HOME');
        
        switch ($this->platform) {
            case 'linux':
            case 'freebsd':
            case 'openbsd':
                $xdgCache = getenv('XDG_CACHE_HOME');
                return $xdgCache ?: ($home . '/.cache');
            case 'darwin':
                return $home . '/Library/Caches';
            default:
                return $this->getTempDir();
        }
    }
    
    public function getLogDir() {
        switch ($this->platform) {
            case 'linux':
            case 'freebsd':
            case 'openbsd':
                // ユーザー権限の場合
                if (posix_getuid() !== 0) {
                    return getenv('HOME') . '/.local/var/log';
                }
                return '/var/log';
            case 'darwin':
                return '/var/log';
            default:
                return $this->getTempDir();
        }
    }
    
    public function getExecutablePath($name) {
        $paths = explode(':', getenv('PATH') ?: '');
        
        foreach ($paths as $dir) {
            $fullPath = $dir . '/' . $name;
            if (file_exists($fullPath) && is_executable($fullPath)) {
                return $fullPath;
            }
        }
        
        return null;
    }
    
    public function printPaths() {
        echo "=== プラットフォーム固有のパス ===\n";
        echo "プラットフォーム: {$this->uname['sysname']}\n\n";
        echo "一時ディレクトリ: " . $this->getTempDir() . "\n";
        echo "設定ディレクトリ: " . $this->getConfigDir() . "\n";
        echo "データディレクトリ: " . $this->getDataDir() . "\n";
        echo "キャッシュディレクトリ: " . $this->getCacheDir() . "\n";
        echo "ログディレクトリ: " . $this->getLogDir() . "\n";
    }
}

// 使用例
$paths = new PlatformPaths();
$paths->printPaths();

// アプリケーションのディレクトリを作成
$appName = 'myapp';
$configDir = $paths->getConfigDir() . '/' . $appName;
$dataDir = $paths->getDataDir() . '/' . $appName;
$cacheDir = $paths->getCacheDir() . '/' . $appName;

echo "\nアプリケーション用ディレクトリ:\n";
echo "  設定: {$configDir}\n";
echo "  データ: {$dataDir}\n";
echo "  キャッシュ: {$cacheDir}\n";
?>

例4: システム情報ロガー

<?php
class SystemInfoLogger {
    private $logFile;
    private $uname;
    
    public function __construct($logFile = '/tmp/system_info.log') {
        $this->logFile = $logFile;
        $this->uname = posix_uname();
    }
    
    public function logSystemInfo() {
        $info = [
            'timestamp' => date('Y-m-d H:i:s'),
            'system' => $this->uname,
            'php_version' => PHP_VERSION,
            'user' => posix_getpwuid(posix_getuid())['name'],
            'pid' => posix_getpid(),
            'load_average' => sys_getloadavg(),
            'memory_usage' => memory_get_usage(true),
            'memory_peak' => memory_get_peak_usage(true)
        ];
        
        $log = json_encode($info) . "\n";
        file_put_contents($this->logFile, $log, FILE_APPEND);
        
        return $info;
    }
    
    public function getSystemFingerprint() {
        // システムを一意に識別するフィンガープリント
        $data = implode('|', [
            $this->uname['sysname'],
            $this->uname['nodename'],
            $this->uname['release'],
            $this->uname['machine']
        ]);
        
        return md5($data);
    }
    
    public function compareWithPrevious() {
        if (!file_exists($this->logFile)) {
            return null;
        }
        
        $lines = file($this->logFile, FILE_IGNORE_NEW_LINES);
        if (count($lines) < 2) {
            return null;
        }
        
        $current = json_decode(end($lines), true);
        $previous = json_decode($lines[count($lines) - 2], true);
        
        $changes = [];
        
        // システム情報の変更をチェック
        foreach ($current['system'] as $key => $value) {
            if ($value !== $previous['system'][$key]) {
                $changes[$key] = [
                    'old' => $previous['system'][$key],
                    'new' => $value
                ];
            }
        }
        
        return $changes;
    }
    
    public function analyze() {
        if (!file_exists($this->logFile)) {
            echo "ログファイルが見つかりません\n";
            return;
        }
        
        $lines = file($this->logFile, FILE_IGNORE_NEW_LINES);
        $entries = array_map('json_decode', $lines);
        $entries = array_map(function($e) { return json_decode($e, true); }, $lines);
        
        echo "=== システム情報ログ分析 ===\n\n";
        echo "総エントリ数: " . count($entries) . "\n";
        
        if (count($entries) > 0) {
            $first = $entries[0];
            $last = end($entries);
            
            echo "最初のログ: {$first['timestamp']}\n";
            echo "最後のログ: {$last['timestamp']}\n";
            
            // システム情報
            echo "\n【システム情報(最新)】\n";
            foreach ($last['system'] as $key => $value) {
                echo "  " . ucfirst($key) . ": {$value}\n";
            }
        }
    }
}

// 使用例
$logger = new SystemInfoLogger();

// システム情報をログ
$info = $logger->logSystemInfo();
echo "システム情報をログに記録しました\n";

// フィンガープリント
echo "システムフィンガープリント: " . $logger->getSystemFingerprint() . "\n";

// 変更をチェック
$changes = $logger->compareWithPrevious();
if ($changes && count($changes) > 0) {
    echo "\n変更が検出されました:\n";
    foreach ($changes as $key => $change) {
        echo "  {$key}: {$change['old']} -> {$change['new']}\n";
    }
}

// ログ分析
echo "\n";
$logger->analyze();
?>

まとめ

posix_unameは、システムに関する包括的な情報を取得できる重要な関数です。

重要なポイント:

  • OS名、ホスト名、カーネルバージョン、アーキテクチャを取得
  • クロスプラットフォーム対応のコード作成に不可欠
  • UNIXコマンドのunameと同等の情報
  • システム互換性チェックに最適

主な用途:

  • OS判定とプラットフォーム固有の処理
  • システム要件のチェック
  • システム情報のログ記録
  • デバッグ情報の収集

ベストプラクティス:

  • システム情報を早期にキャッシュする
  • OS別の処理を適切に分岐
  • システム情報をログに含める
  • 互換性チェックを自動化

posix_unameを活用することで、移植性の高いPHPアプリケーションを開発し、様々なプラットフォームで安定して動作させることができます!


関連記事:

  • php_uname(): PHPネイティブのシステム情報取得
  • PHP_OS: OSの名前を示す定数
  • PHP_OS_FAMILY: OSファミリーを示す定数(PHP 7.2+)
  • sys_get_temp_dir(): 一時ディレクトリのパスを取得
  • getenv(): 環境変数を取得
タイトルとURLをコピーしました