Files
static-php-cli/src/StaticPHP/Util/System/LinuxUtil.php

159 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
namespace StaticPHP\Util\System;
class LinuxUtil extends UnixUtil
{
/** @var null|string libc version cache */
public static ?string $libc_version = null;
/**
* Get current linux distro name and version.
*
* @return array{dist: string, ver: string, family: string} Linux distro info (unknown if not found)
*/
public static function getOSRelease(): array
{
$ret = [
'dist' => 'unknown',
'ver' => 'unknown',
'family' => 'unknown',
];
if (file_exists('/etc/centos-release') || file_exists('/etc/redhat-release')) {
$is_centos = file_exists('/etc/centos-release');
$file = $is_centos ? '/etc/centos-release' : '/etc/redhat-release';
$lines = file($file);
foreach ($lines as $line) {
if (preg_match('/release\s+(\d*(\.\d+)*)/', $line, $matches)) {
$ret['dist'] = $is_centos ? 'centos' : 'redhat';
$ret['ver'] = $matches[1];
}
}
} elseif (file_exists('/etc/os-release')) {
$lines = file('/etc/os-release');
foreach ($lines as $line) {
if (preg_match('/^ID=(.*)$/', $line, $matches)) {
$ret['dist'] = $matches[1];
}
if (preg_match('/^ID_LIKE=(.*)$/', $line, $matches)) {
$ret['family'] = $matches[1];
}
if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) {
$ret['ver'] = $matches[1];
}
}
$ret['dist'] = trim($ret['dist'], '"\'');
$ret['ver'] = trim($ret['ver'], '"\'');
if (strcasecmp($ret['dist'], 'centos') === 0) {
$ret['dist'] = 'redhat';
}
}
return $ret;
}
/**
* Check if current linux distro is musl-based (alpine).
*/
public static function isMuslDist(): bool
{
return static::getOSRelease()['dist'] === 'alpine';
}
/**
* Get CPU core count.
*/
public static function getCpuCount(): int
{
$ncpu = 1;
if (is_file('/proc/cpuinfo')) {
$cpuinfo = file_get_contents('/proc/cpuinfo');
preg_match_all('/^processor/m', $cpuinfo, $matches);
$ncpu = count($matches[0]);
}
return $ncpu;
}
/**
* Get fully-supported linux distros.
*
* @return string[] List of supported Linux distro name for doctor
*/
public static function getSupportedDistros(): array
{
return [
// debian-like
'debian', 'ubuntu', 'Deepin', 'neon',
// rhel-like
'redhat',
// centos
'centos',
// alpine
'alpine',
// arch
'arch', 'manjaro',
];
}
/**
* Check if current linux distro is debian-based.
*/
public static function isDebianDist(): bool
{
$dist = static::getOSRelease()['dist'];
$family = explode(' ', static::getOSRelease()['family']);
return in_array($dist, ['debian', 'ubuntu', 'Deepin', 'neon']) || in_array('debian', $family);
}
/**
* Get libc version string from ldd.
*/
public static function getLibcVersionIfExists(?string $libc = null): ?string
{
if (self::$libc_version !== null) {
return self::$libc_version;
}
if ($libc === 'glibc') {
$result = shell()->execWithResult('ldd --version', false);
if ($result[0] !== 0) {
return null;
}
// get first line
$first_line = $result[1][0];
// match ldd version: "ldd (some useless text) 2.17" match 2.17
$pattern = '/ldd\s+\(.*?\)\s+(\d+\.\d+)/';
if (preg_match($pattern, $first_line, $matches)) {
self::$libc_version = $matches[1];
return self::$libc_version;
}
return null;
}
if ($libc === 'musl') {
if (self::isMuslDist()) {
$result = shell()->execWithResult('ldd 2>&1', false);
} elseif (is_file('/usr/local/musl/lib/libc.so')) {
$result = shell()->execWithResult('/usr/local/musl/lib/libc.so 2>&1', false);
} else {
$arch = php_uname('m');
$result = shell()->execWithResult("/lib/ld-musl-{$arch}.so.1 2>&1", false);
}
// Match Version * line
// match ldd version: "Version 1.2.3" match 1.2.3
$pattern = '/Version\s+(\d+\.\d+\.\d+)/';
if (preg_match($pattern, $result[1][1] ?? '', $matches)) {
self::$libc_version = $matches[1];
return self::$libc_version;
}
}
return null;
}
}