| 1: | <?php
|
| 2: | |
| 3: | |
| 4: |
|
| 5: | class extensions{
|
| 6: |
|
| 7: | |
| 8: | |
| 9: | |
| 10: | |
| 11: | |
| 12: |
|
| 13: | public static function windowsPeclUrl(string $extension):?string{
|
| 14: | if(!preg_match('/^[a-z0-9_-]{1,64}$/', $extension)){
|
| 15: | mklog0(3, "Invalid extension name $extension");
|
| 16: | return false;
|
| 17: | }
|
| 18: |
|
| 19: | if(!extension_loaded('openssl')){
|
| 20: | mklog0(3, "OpenSSL extension not enabled, this is needed to access pecl.php.net");
|
| 21: | return false;
|
| 22: | }
|
| 23: |
|
| 24: | $version = trim(@file_get_contents("https://pecl.php.net/rest/r/$extension/stable.txt"));
|
| 25: | if(!$version){
|
| 26: | mklog0(3, "Failed to get latest version for $extension");
|
| 27: | return null;
|
| 28: | }
|
| 29: |
|
| 30: | $build = self::buildInfo();
|
| 31: | $phpVer = self::phpVersion();
|
| 32: | $arch = PHP_INT_SIZE === 8 ? 'x64' : 'x86';
|
| 33: | $filename = "php_$extension-$version-$phpVer-" . $build['ts'] . "-" . $build['vs'] . "-$arch.zip";
|
| 34: | $url = "https://windows.php.net/downloads/pecl/releases/$extension/$version/$filename";
|
| 35: |
|
| 36: |
|
| 37: | $headers = @get_headers($url);
|
| 38: | if(!$headers || !str_contains($headers[0], '200')){
|
| 39: | mklog0(3, "Could not get compatible version for $extension");
|
| 40: | return null;
|
| 41: | }
|
| 42: |
|
| 43: | return $url;
|
| 44: | }
|
| 45: | |
| 46: | |
| 47: | |
| 48: | |
| 49: | |
| 50: | |
| 51: |
|
| 52: | public static function windowsInstallPeclExtension(string $extension, ?string $dest_dir=null):bool{
|
| 53: | $url = self::windowsPeclUrl($extension);
|
| 54: | if(!$url){
|
| 55: | mklog0(2, "No Windows build found for $extension matching your PHP config");
|
| 56: | return false;
|
| 57: | }
|
| 58: |
|
| 59: | $dest_dir = $dest_dir ?? ini_get('extension_dir');
|
| 60: | if(!$dest_dir){
|
| 61: | mklog0(3, 'Could not determine extension directory');
|
| 62: | return false;
|
| 63: | }
|
| 64: |
|
| 65: | $filename = basename($url);
|
| 66: | $tmp_zip = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $filename;
|
| 67: |
|
| 68: |
|
| 69: | mklog0(1, "Downloading $filename");
|
| 70: | $zip_data = file_get_contents($url);
|
| 71: | if(!$zip_data){
|
| 72: | mklog0(3, "Failed to download $filename");
|
| 73: | return false;
|
| 74: | }
|
| 75: | if(!file_put_contents($tmp_zip, $zip_data)){
|
| 76: | mklog0(3, "Failed to save $filename");
|
| 77: | return false;
|
| 78: | }
|
| 79: |
|
| 80: |
|
| 81: | $zip = new ZipArchive();
|
| 82: | if($zip->open($tmp_zip) !== true){
|
| 83: | mklog0(3, "Failed to open zip $tmp_zip");
|
| 84: | unlink($tmp_zip);
|
| 85: | return false;
|
| 86: | }
|
| 87: |
|
| 88: | $dll_name = "php_$extension.dll";
|
| 89: | $dest = rtrim($dest_dir, '\\/') . "/" . $dll_name;
|
| 90: |
|
| 91: | if($zip->locateName($dll_name) === false){
|
| 92: | mklog0(3, "Could not find $dll_name in downloaded zip");
|
| 93: | $zip->close();
|
| 94: | unlink($tmp_zip);
|
| 95: | return false;
|
| 96: | }
|
| 97: |
|
| 98: | if(file_put_contents($dest, $zip->getFromName($dll_name))){
|
| 99: | mklog0(3, "Failed to save dll from downloaded zip to extension dir");
|
| 100: | $zip->close();
|
| 101: | unlink($tmp_zip);
|
| 102: | return false;
|
| 103: | }
|
| 104: |
|
| 105: | $zip->close();
|
| 106: | unlink($tmp_zip);
|
| 107: |
|
| 108: | mklog0(1, "Installed $dll_name to $dest");
|
| 109: | return true;
|
| 110: | }
|
| 111: |
|
| 112: | |
| 113: | |
| 114: | |
| 115: | |
| 116: |
|
| 117: | public static function linuxEnsurePhpRepo():bool{
|
| 118: |
|
| 119: | exec("grep -rq 'ondrej/php' /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null", $_, $grepExit);
|
| 120: | if($grepExit === 0){
|
| 121: |
|
| 122: | return true;
|
| 123: | }
|
| 124: |
|
| 125: |
|
| 126: | exec("command -v add-apt-repository 2>/dev/null", $_, $cmdExit);
|
| 127: | if($cmdExit !== 0){
|
| 128: | mklog0(1, "add-apt-repository command not found. Installing software-properties-common");
|
| 129: |
|
| 130: | if(!linuxcmd::updateApt()){
|
| 131: | mklog0(2, "Failed to run apt update, package versions may be out of date, continuing");
|
| 132: | }
|
| 133: |
|
| 134: | if(linuxcmd::sudo("apt install software-properties-common -y -qq") !== 0) {
|
| 135: | mklog0(3, "Failed to install software-properties-common");
|
| 136: | return false;
|
| 137: | }
|
| 138: | }
|
| 139: |
|
| 140: |
|
| 141: | mklog(1, "Adding ondrej/php apt repository");
|
| 142: | if(linuxcmd::sudo("LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -y") !== 0){
|
| 143: | mklog0(3, "Failed to add ondrej/php apt repository");
|
| 144: | return false;
|
| 145: | }
|
| 146: |
|
| 147: |
|
| 148: | if(!linuxcmd::updateApt(true)){
|
| 149: | mklog0(3, "Failed to update apt after adding ondrej/php repository");
|
| 150: | return false;
|
| 151: | }
|
| 152: |
|
| 153: | return true;
|
| 154: | }
|
| 155: |
|
| 156: |
|
| 157: | |
| 158: | |
| 159: | |
| 160: | |
| 161: | |
| 162: |
|
| 163: | public static function ensure(string $extension):bool{
|
| 164: | if(extension_loaded($extension)){
|
| 165: | return true;
|
| 166: | }
|
| 167: |
|
| 168: | self::setEnabled($extension, true);
|
| 169: | return false;
|
| 170: | }
|
| 171: | |
| 172: | |
| 173: | |
| 174: | |
| 175: | |
| 176: | |
| 177: | |
| 178: |
|
| 179: | public static function extensionInfo():array{
|
| 180: | return [
|
| 181: | 'builtin' => [
|
| 182: | 'Linux' => [
|
| 183: | 'core','date','filter','hash','json','lexbor','libxml','openssl','pcntl','pcre','random','reflextion','session','sodium','spl','standard','uri','Zend OPcache','zlib'
|
| 184: | ],
|
| 185: | 'Windows' => [
|
| 186: | 'bcmath','calendar','core','ctype','date','dom','filter','hash','iconv','json','lexbor','libxml','mysqlnd','pcre','pdo','phar','random','readline','reflection','session','simplexml','spl','standard','tokenizer','uri','xml','xmlreader','xmlwriter','Zend OPcache','zlib'
|
| 187: | ]
|
| 188: | ],
|
| 189: | 'bundled' => [
|
| 190: | 'Linux' => [
|
| 191: | 'calendar','ctype','exif','ffi','fileinfo','ftp','gettext','iconv','pdo','phar','posix','readline','shmop','sockets','sysvmsg','sysvsem','sysvshm','tokenizer'
|
| 192: | ],
|
| 193: | 'Windows' => [
|
| 194: | 'bz2','com_dotnet','curl','dba','enchant','exif','ffi','fileinfo','ftp','gd','gettext','gmp','intl','ldap','mbstring','mysqli','odbc','openssl','pdo_firebird','pdo_mysql','pdo_odbc','pdo_pgsql','pdo_sqlite','pgsql','shmop','snmp','soap','sockets','sodium','sqlite3','sysvshm','tidy','xsl','zip'
|
| 195: | ]
|
| 196: | ],
|
| 197: | 'installnames' => [
|
| 198: | 'Linux' => [
|
| 199: | 'mysqli' => 'mysql',
|
| 200: | 'pdo_mysql' => 'mysql',
|
| 201: | 'pdo_odbc' => 'odbc',
|
| 202: | 'pdo_pgsql' => 'pgsql',
|
| 203: | 'pdo_sqlite' => 'sqlite3',
|
| 204: | 'pdo_dblib' => 'sybase',
|
| 205: | 'dom' => 'xml',
|
| 206: | 'simplexml' => 'xml',
|
| 207: | 'xmlreader' => 'xml',
|
| 208: | 'xmlwriter' => 'xml',
|
| 209: | 'xsl' => 'xml',
|
| 210: | ],
|
| 211: | 'Windows' => []
|
| 212: | ]
|
| 213: | ];
|
| 214: | }
|
| 215: | |
| 216: | |
| 217: | |
| 218: | |
| 219: |
|
| 220: | public static function buildInfo():array{
|
| 221: | ob_start();
|
| 222: | phpinfo(INFO_GENERAL);
|
| 223: | $info = ob_get_clean();
|
| 224: |
|
| 225: |
|
| 226: | if(preg_match('/PHP Extension Build\s*=>\s*API\d+,(\w+),(VS\d+)/i', $info, $m)){
|
| 227: | return [
|
| 228: | 'ts' => strtolower($m[1]),
|
| 229: | 'vs' => strtolower($m[2]),
|
| 230: | ];
|
| 231: | }
|
| 232: |
|
| 233: | mklog0(1, "Using fallback build info");
|
| 234: |
|
| 235: |
|
| 236: | return [
|
| 237: | 'ts' => ZEND_THREAD_SAFE ? 'ts' : 'nts',
|
| 238: | 'vs' => 'vs17',
|
| 239: | ];
|
| 240: | }
|
| 241: | |
| 242: | |
| 243: | |
| 244: | |
| 245: | |
| 246: |
|
| 247: | public static function areLoaded(array $extensions):bool{
|
| 248: | $areLoaded = true;
|
| 249: |
|
| 250: | foreach($extensions as $extension){
|
| 251: | if(!extension_loaded($extension)){
|
| 252: | $areLoaded = false;
|
| 253: | break;
|
| 254: | }
|
| 255: | }
|
| 256: |
|
| 257: | return $areLoaded;
|
| 258: | }
|
| 259: | |
| 260: | |
| 261: | |
| 262: | |
| 263: |
|
| 264: | public static function phpVersion():string{
|
| 265: | return PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
|
| 266: | }
|
| 267: | |
| 268: | |
| 269: | |
| 270: | |
| 271: | |
| 272: | |
| 273: | |
| 274: |
|
| 275: | public static function setEnabled(string $extension, bool $enabled=true, bool $allowDownload=true):bool{
|
| 276: | if(!preg_match('/^[a-z0-9_-]{1,64}$/', $extension)){
|
| 277: | mklog0(2, "Invalid extension name $extension");
|
| 278: | return false;
|
| 279: | }
|
| 280: |
|
| 281: | if(extension_loaded($extension) && $enabled){
|
| 282: | mklog0(1, "Extension $extension is already enabled");
|
| 283: | return true;
|
| 284: | }
|
| 285: |
|
| 286: | if(self::installed($extension)){
|
| 287: | mklog0(1, "Enabling extension " . $extension . (function_exists('mklog') ? ", you will need to restart PHP-CLI for the extension to become loaded" : ""));
|
| 288: | if(PHP_OS_FAMILY === 'Linux'){
|
| 289: | $exit = linuxcmd::sudo(($enabled ? "phpenmod " : "phpdismod ") . $extension);
|
| 290: | if($exit !== 0){
|
| 291: | mklog0(3, ($enabled ? "phpenmod " : "phpdismod ") . " command reported error code " . $exit);
|
| 292: | return false;
|
| 293: | }
|
| 294: | return true;
|
| 295: | }
|
| 296: | else{
|
| 297: | return inimgmt::windowsEnableExtension($extension, $enabled);
|
| 298: | }
|
| 299: | }
|
| 300: |
|
| 301: | if(!$enabled){
|
| 302: | return true;
|
| 303: | }
|
| 304: |
|
| 305: | if(!$allowDownload){
|
| 306: | mklog0(3, "Extension $extension is not installed and allowDownload is false");
|
| 307: | return false;
|
| 308: | }
|
| 309: |
|
| 310: | mklog0(1, "Installing extension " . $extension);
|
| 311: | if(!self::install($extension)){
|
| 312: | mklog0(3, "Failed to install " . $extension);
|
| 313: | return false;
|
| 314: | }
|
| 315: |
|
| 316: | if(!self::setEnabled($extension, true, false)){
|
| 317: | mklog0(3, "Failed to enable " . $extension . " after install");
|
| 318: | return false;
|
| 319: | }
|
| 320: |
|
| 321: | return true;
|
| 322: | }
|
| 323: | |
| 324: | |
| 325: | |
| 326: | |
| 327: | |
| 328: |
|
| 329: | public static function install(string $extension):bool{
|
| 330: | if(!preg_match('/^[a-z0-9_-]{1,64}$/', $extension)){
|
| 331: | mklog0(2, "Invalid extension name $extension");
|
| 332: | return false;
|
| 333: | }
|
| 334: |
|
| 335: | $extensionName = $extension;
|
| 336: | $nicknames = self::extensionInfo()['installnames'][PHP_OS_FAMILY];
|
| 337: | if(isset($nicknames[$extension])){
|
| 338: | $extensionName = $nicknames[$extension];
|
| 339: | }
|
| 340: |
|
| 341: | if(PHP_OS_FAMILY === 'Linux'){
|
| 342: | if(!self::linuxEnsurePhpRepo()){
|
| 343: | mklog0(3, "Failed to ensure the ondrej/php apt repository was enabled");
|
| 344: | return false;
|
| 345: | }
|
| 346: |
|
| 347: | $command = "apt install php" . self::phpVersion() . "-" . $extensionName . " -y";
|
| 348: | if(linuxcmd::sudo($command) !== 0){
|
| 349: | mklog0(3, "Failed to run " . $command);
|
| 350: | return false;
|
| 351: | }
|
| 352: | }
|
| 353: | else{
|
| 354: | if(!self::windowsInstallPeclExtension($extensionName)){
|
| 355: | mklog0(3, "Failed to download pecl extension " . $extensionName);
|
| 356: | return false;
|
| 357: | }
|
| 358: | }
|
| 359: |
|
| 360: | return true;
|
| 361: | }
|
| 362: | |
| 363: | |
| 364: | |
| 365: | |
| 366: | |
| 367: |
|
| 368: | public static function installed(string $extension):bool{
|
| 369: | if(!preg_match('/^[a-z0-9_-]{1,64}$/', $extension)){
|
| 370: | mklog0(2, "Invalid extension name $extension");
|
| 371: | return false;
|
| 372: | }
|
| 373: |
|
| 374: | $extensionDir = ini_get('extension_dir');
|
| 375: | if(PHP_OS_FAMILY === 'Linux'){
|
| 376: | $extensionFile = $extension . ".so";
|
| 377: | }
|
| 378: | else{
|
| 379: | $extensionFile = "php_" . $extension . ".dll";
|
| 380: | }
|
| 381: |
|
| 382: | return file_exists($extensionDir . "/" . $extensionFile);
|
| 383: | }
|
| 384: | }
|
| 385: | |
| 386: | |
| 387: |
|
| 388: | class inimgmt{
|
| 389: | |
| 390: | |
| 391: | |
| 392: | |
| 393: |
|
| 394: | public static function cliHardCoded():array{
|
| 395: | return [
|
| 396: | 'html_errors',
|
| 397: | 'implicit_flush',
|
| 398: | 'max_execution_time',
|
| 399: | 'memory_limit',
|
| 400: | 'register_argc_argv',
|
| 401: | 'output_buffering',
|
| 402: | 'max_input_time',
|
| 403: | ];
|
| 404: | }
|
| 405: | |
| 406: | |
| 407: | |
| 408: | |
| 409: | |
| 410: | |
| 411: | |
| 412: |
|
| 413: | public static function replaceLineBeginingWith(array &$lines, string $starting, string $replacement):bool{
|
| 414: | $count = strlen($starting);
|
| 415: | $somethingHappened = false;
|
| 416: | foreach($lines as $index => $line){
|
| 417: | $line = trim($line);
|
| 418: | if(empty($line)){
|
| 419: | continue;
|
| 420: | }
|
| 421: |
|
| 422: | if(substr($line,0,$count) === $starting){
|
| 423: | $lines[$index] = $replacement . "\n";
|
| 424: | $somethingHappened = true;
|
| 425: | break;
|
| 426: | }
|
| 427: | }
|
| 428: |
|
| 429: | return $somethingHappened;
|
| 430: | }
|
| 431: | |
| 432: | |
| 433: | |
| 434: | |
| 435: | |
| 436: |
|
| 437: | public static function doesSettingsMatch(array $expected):bool{
|
| 438: | $allMatch = true;
|
| 439: | $cliHardCoded = inimgmt::cliHardCoded();
|
| 440: |
|
| 441: | foreach($expected as $settingName => $settingValue){
|
| 442: | if(in_array($settingName, $cliHardCoded)){
|
| 443: | continue;
|
| 444: | }
|
| 445: |
|
| 446: | $iniSetting = ini_get($settingName);
|
| 447: |
|
| 448: | if($iniSetting !== $settingValue){
|
| 449: | $allMatch = false;
|
| 450: | break;
|
| 451: | }
|
| 452: | }
|
| 453: |
|
| 454: | return $allMatch;
|
| 455: | }
|
| 456: | |
| 457: | |
| 458: | |
| 459: | |
| 460: |
|
| 461: | public static function iniPath():?string{
|
| 462: | $iniPath = php_ini_loaded_file();
|
| 463: | if(!is_string($iniPath) || !file_exists($iniPath)){
|
| 464: | return null;
|
| 465: | }
|
| 466: | return $iniPath;
|
| 467: | }
|
| 468: | |
| 469: | |
| 470: | |
| 471: | |
| 472: |
|
| 473: | public static function backupIni():bool{
|
| 474: | $iniPath = self::iniPath();
|
| 475: | if(!$iniPath){
|
| 476: | return false;
|
| 477: | }
|
| 478: |
|
| 479: | $backupPath = $iniPath . date('.Y-m-d_H-i-s') . '.bak';
|
| 480: |
|
| 481: | return copy($iniPath, $backupPath);
|
| 482: | }
|
| 483: | |
| 484: | |
| 485: | |
| 486: | |
| 487: | |
| 488: |
|
| 489: | public static function loadIni(bool $checkWriteable=true):?array{
|
| 490: | $path = self::iniPath();
|
| 491: | if(!$path){
|
| 492: | return null;
|
| 493: | }
|
| 494: |
|
| 495: | if($checkWriteable && !is_writable($path)){
|
| 496: | return null;
|
| 497: | }
|
| 498: |
|
| 499: | $lines = file($path);
|
| 500: | if(!is_array($lines)){
|
| 501: | return null;
|
| 502: | }
|
| 503: |
|
| 504: | return $lines;
|
| 505: | }
|
| 506: | |
| 507: | |
| 508: | |
| 509: | |
| 510: | |
| 511: | |
| 512: |
|
| 513: | public static function setSettingsOnLines(array &$lines, array $settings):bool{
|
| 514: | $success = true;
|
| 515: | foreach($settings as $settingName => $settingValue){
|
| 516: | $replacement = $settingName . " = " . $settingValue;
|
| 517: | if(!self::replaceLineBeginingWith($lines, $settingName, $replacement)){
|
| 518: | if(!self::replaceLineBeginingWith($lines, ';' . $settingName, $replacement)){
|
| 519: | $success = false;
|
| 520: | }
|
| 521: | }
|
| 522: | }
|
| 523: | return $success;
|
| 524: | }
|
| 525: | |
| 526: | |
| 527: | |
| 528: | |
| 529: | |
| 530: | |
| 531: | |
| 532: |
|
| 533: | public static function windowsEnableExtension(string $extension, bool $enabled, bool $backupIni=true):bool{
|
| 534: | if(!preg_match('/^[a-z0-9_-]{1,64}$/', $extension)){
|
| 535: | mklog0(2, "Invalid extension name $extension");
|
| 536: | return false;
|
| 537: | }
|
| 538: |
|
| 539: | if(extension_loaded($extension) && $enabled){
|
| 540: | mklog0(1, "Extension $extension is already enabled");
|
| 541: | return true;
|
| 542: | }
|
| 543: |
|
| 544: | $lines = self::loadIni();
|
| 545: | if(!$lines){
|
| 546: | mklog0(2,"Failed to load php.ini");
|
| 547: | return false;
|
| 548: | }
|
| 549: |
|
| 550: | $extensionLine = "extension=" . $extension;
|
| 551: | $extensionLineIndex = null;
|
| 552: | foreach($lines as $index => $line){
|
| 553: | if(str_contains(str_replace(" ", "", $line), $extensionLine)){
|
| 554: | $extensionLineIndex = $index;
|
| 555: | break;
|
| 556: | }
|
| 557: | }
|
| 558: |
|
| 559: | if($extensionLineIndex === null){
|
| 560: | $lastExtensionIndex = count($lines)-1;
|
| 561: | foreach($lines as $index => $line){
|
| 562: | if(str_contains($line, "extension=")){
|
| 563: | $lastExtensionIndex = $index;
|
| 564: | }
|
| 565: | }
|
| 566: |
|
| 567: | array_splice($lines, $lastExtensionIndex, 0, ["\n"]);
|
| 568: | $extensionLineIndex = $lastExtensionIndex +1;
|
| 569: | }
|
| 570: |
|
| 571: | $lines[$extensionLineIndex] = ($enabled ? "" : ";") . $extensionLine . "\n";
|
| 572: |
|
| 573: | return self::saveIni($lines, $backupIni);
|
| 574: | }
|
| 575: | |
| 576: | |
| 577: | |
| 578: | |
| 579: | |
| 580: |
|
| 581: | public static function setIniSettings(array $settings):bool{
|
| 582: | $lines = self::loadIni();
|
| 583: | if(!$lines){
|
| 584: | mklog0(3, "Failed to load php.ini");
|
| 585: | return false;
|
| 586: | }
|
| 587: |
|
| 588: | if(!self::setSettingsOnLines($lines, $settings)){
|
| 589: | mklog0(3, "Failed to set ini settings");
|
| 590: | return false;
|
| 591: | }
|
| 592: |
|
| 593: | if(!self::saveIni($lines)){
|
| 594: | mklog0(3, "Failed to save php.ini");
|
| 595: | return false;
|
| 596: | }
|
| 597: |
|
| 598: | return true;
|
| 599: | }
|
| 600: | |
| 601: | |
| 602: | |
| 603: | |
| 604: | |
| 605: | |
| 606: |
|
| 607: | public static function saveIni(array $lines, bool $backup=true):bool{
|
| 608: | if($backup){
|
| 609: | if(!self::backupIni()){
|
| 610: | mklog0(3, "Failed to create backup of php.ini before modification");
|
| 611: | return false;
|
| 612: | }
|
| 613: | }
|
| 614: |
|
| 615: | $path = self::iniPath();
|
| 616: | if(!$path){
|
| 617: | return false;
|
| 618: | }
|
| 619: |
|
| 620: | return file_put_contents($path, $lines) !== false;
|
| 621: | }
|
| 622: | }
|
| 623: | |
| 624: | |
| 625: |
|
| 626: | class is_admin{
|
| 627: | private static ?bool $state = null;
|
| 628: |
|
| 629: | |
| 630: | |
| 631: | |
| 632: | |
| 633: |
|
| 634: | public static function check():bool{
|
| 635: | if(!is_bool(self::$state)){
|
| 636: | mklog(0,"Checking for Administrator privilages");
|
| 637: |
|
| 638: | if(PHP_OS_FAMILY === 'Linux'){
|
| 639: | self::$state = (posix_geteuid() === 0);
|
| 640: | }
|
| 641: | else{
|
| 642: | exec("net session >nul 2>&1", $_, $resultCode);
|
| 643: | self::$state = ($resultCode === 0);
|
| 644: | }
|
| 645: | }
|
| 646: |
|
| 647: | return self::$state;
|
| 648: | }
|
| 649: | |
| 650: | |
| 651: | |
| 652: | |
| 653: |
|
| 654: | public static function refresh():bool{
|
| 655: | self::$state = null;
|
| 656: | return self::check();
|
| 657: | }
|
| 658: | }
|
| 659: | |
| 660: | |
| 661: |
|
| 662: | class linuxcmd{
|
| 663: | |
| 664: | |
| 665: |
|
| 666: | private static $lastAptUpdate = 0;
|
| 667: |
|
| 668: | |
| 669: | |
| 670: | |
| 671: | |
| 672: | |
| 673: |
|
| 674: | public static function sudo(string $command):int{
|
| 675: |
|
| 676: | $process = proc_open('sudo ' . $command, [
|
| 677: | 0 => STDIN,
|
| 678: | 1 => ['file', '/dev/null', 'w'],
|
| 679: | 2 => ['file', '/dev/null', 'w'],
|
| 680: | ], $pipes);
|
| 681: |
|
| 682: | return proc_close($process);
|
| 683: | }
|
| 684: | |
| 685: | |
| 686: | |
| 687: | |
| 688: | |
| 689: |
|
| 690: | public static function isAptPackageInstalled(string $package):bool{
|
| 691: | exec('dpkg-query -W ' . escapeshellarg($package), $output, $exitCode);
|
| 692: | return $exitCode === 0;
|
| 693: | }
|
| 694: | |
| 695: | |
| 696: | |
| 697: | |
| 698: | |
| 699: |
|
| 700: | public static function updateApt(bool $ignoreTimeout=false):bool{
|
| 701: | if(time() - self::$lastAptUpdate > 3600 && !$ignoreTimeout){
|
| 702: | return true;
|
| 703: | }
|
| 704: |
|
| 705: | mklog0(1, "Running apt update");
|
| 706: |
|
| 707: | if(self::sudo("apt update") === 0){
|
| 708: | self::$lastAptUpdate = time();
|
| 709: | return true;
|
| 710: | }
|
| 711: | return false;
|
| 712: | }
|
| 713: | }
|
| 714: | |
| 715: | |
| 716: | |
| 717: | |
| 718: | |
| 719: | |
| 720: |
|
| 721: | function mklog0(int $type, string $message):void{
|
| 722: | if(function_exists('mklog')){
|
| 723: | mklog($type, $message);
|
| 724: | }
|
| 725: | else{
|
| 726: | $type = min(max($type,0),3);
|
| 727: | if($type){
|
| 728: | echo ["General","Warning","Error"][$type-1] . ": " . $message . "\n";
|
| 729: | }
|
| 730: | }
|
| 731: | } |