Bearsampp 2026.5.5
Loading...
Searching...
No Matches
ActionStartup Class Reference

Public Member Functions

 __construct ($args)
 processWindow ($window, $id, $ctrl, $param1, $param2)

Data Fields

const GAUGE_OTHERS = 19
const GAUGE_SERVICES = 5

Private Member Functions

 changePath ()
 checkApacheServiceWithTimeout ($service)
 checkBinsRegKey ()
 checkBrowser ()
 checkLaunchStartup ()
 checkMySQLServiceWithTimeout ($service, $bin)
 checkPath ()
 checkPathRegKey ()
 checkSystemPathRegKey ()
 cleanOldBehaviors ()
 cleanTmpFolders ()
 createSslCrts ()
 installServices ()
 installServicesSequential ($bearsamppBins, $bearsamppLang)
 killOldInstances ()
 prepareService ($sName, $service, $bearsamppBins, $bearsamppLang, $currentIndex=0, $totalCount=0)
 refreshAliases ()
 refreshGitRepos ()
 refreshHostname ()
 refreshVhosts ()
 rotationLogs ()
 savePath ()
 scanFolders ()
 sysInfos ()
 updateConfig ()
 writeLog ($log)

Private Attributes

 $error
 $filesToScan
 $restart
 $rootPath
 $splash
 $startTime

Detailed Description

Class ActionStartup Handles the startup process of the Bearsampp application, including initializing services, cleaning temporary files, refreshing configurations, and more.

Definition at line 16 of file class.action.startup.php.

Constructor & Destructor Documentation

◆ __construct()

__construct ( $args)

ActionStartup constructor. Initializes the startup process, including the splash screen and various configurations.

Parameters
array$argsCommand line arguments.

Definition at line 35 of file class.action.startup.php.

36 {
37 global $bearsamppRoot, $bearsamppCore, $bearsamppLang, $bearsamppBins, $bearsamppWinbinder;
38 $this->writeLog( 'Starting ' . APP_TITLE );
39
40 // Admin check is now performed in root.php before ActionStartup is instantiated
41 // This prevents screen flashes and ensures the check happens before any WinBinder initialization
42 Log::info('Administrator privileges confirmed - proceeding with startup');
43
44 // Init
45 $this->splash = new Splash();
46 $this->restart = false;
47 $this->startTime = Util::getMicrotime();
48 $this->error = '';
49
50 $this->rootPath = $bearsamppRoot->getRootPath();
51 $this->filesToScan = array();
52
53 $gauge = self::GAUGE_SERVICES * count( $bearsamppBins->getServices() );
54 $gauge += self::GAUGE_OTHERS + 1;
55
56 // Start splash screen
57 $this->splash->init(
58 $bearsamppLang->getValue( Lang::STARTUP ),
59 $gauge,
60 sprintf( $bearsamppLang->getValue( Lang::STARTUP_STARTING_TEXT ), APP_TITLE . ' ' . $bearsamppCore->getAppVersion() )
61 );
62
63 $bearsamppWinbinder->setHandler( $this->splash->getWbWindow(), $this, 'processWindow', 1000 );
64 $bearsamppWinbinder->mainLoop();
65 $bearsamppWinbinder->reset();
66 }
global $bearsamppBins
global $bearsamppLang
global $bearsamppRoot
global $bearsamppCore
const STARTUP_STARTING_TEXT
const STARTUP
static info($data, $file=null)
static getMicrotime()
const APP_TITLE
Definition root.php:13

References $bearsamppBins, $bearsamppCore, $bearsamppLang, $bearsamppRoot, APP_TITLE, Util\getMicrotime(), Log\info(), Lang\STARTUP, Lang\STARTUP_STARTING_TEXT, and writeLog().

Member Function Documentation

◆ changePath()

changePath ( )
private

Changes the application path and logs the number of files and occurrences changed.

Definition at line 725 of file class.action.startup.php.

726 {
727 global $bearsamppLang;
728
729 $this->splash->setTextLoading( sprintf( $bearsamppLang->getValue( Lang::STARTUP_CHANGE_PATH_TEXT ), $this->rootPath ) );
730 $this->splash->incrProgressBar();
731
732 $result = Util::changePath( $this->filesToScan, $this->rootPath );
733 $this->writeLog( 'Nb files changed: ' . $result['countChangedFiles'] );
734 $this->writeLog( 'Nb occurences changed: ' . $result['countChangedOcc'] );
735 }
$result
const STARTUP_CHANGE_PATH_TEXT
static changePath($filesToScan, $rootPath=null)

References $bearsamppLang, $result, Util\changePath(), Lang\STARTUP_CHANGE_PATH_TEXT, and writeLog().

Referenced by processWindow().

◆ checkApacheServiceWithTimeout()

checkApacheServiceWithTimeout ( $service)
private

Specialized method to check Apache service with timeout protection. Apache service checks can sometimes hang, so this method provides a safer way to check.

Parameters
object$serviceThe Apache service object
Returns
mixed Service info array or false if service not installed or check timed out

Definition at line 1227 of file class.action.startup.php.

1228 {
1229 Log::trace('Starting specialized Apache service check with timeout protection');
1230
1231 // Set a timeout for the Apache service check
1232 $serviceCheckStartTime = microtime(true);
1233 $serviceCheckTimeout = 10; // 10 seconds timeout
1234
1235 try {
1236 // Use a non-blocking approach to check service
1237 $serviceInfos = false;
1238
1239 // First try a quick check if the service exists in the list
1240 $serviceList = Win32Service::getServices();
1241 if (is_array($serviceList) && isset($serviceList[$service->getName()])) {
1242 Log::trace('Apache service found in service list, getting details');
1243
1244 // Service exists, now try to get its details with timeout protection
1245 $startTime = microtime(true);
1246 $serviceInfos = $service->infos();
1247
1248 // Check if we've exceeded our timeout
1249 if (microtime(true) - $serviceCheckStartTime > $serviceCheckTimeout) {
1250 Log::trace("Apache service check timeout exceeded, assuming service needs reinstall");
1251 return false;
1252 }
1253 } else {
1254 Log::trace('Apache service not found in service list');
1255 return false;
1256 }
1257
1258 return $serviceInfos;
1259 } catch (\Exception $e) {
1260 Log::trace("Exception during Apache service check: " . $e->getMessage());
1261 return false;
1262 } catch (\Throwable $e) {
1263 Log::trace("Throwable during Apache service check: " . $e->getMessage());
1264 return false;
1265 }
1266 }
static trace($data, $file=null)

References $startTime, and Log\trace().

Referenced by prepareService().

◆ checkBinsRegKey()

checkBinsRegKey ( )
private

Checks and updates the application bins registry key. If the current registry key does not match the generated key, it updates the registry key. Logs the current and generated registry keys. Sets an error message if the registry key update fails. Sets a restart flag if the registry key is updated.

Definition at line 784 of file class.action.startup.php.

785 {
786 global $bearsamppLang, $bearsamppRegistry;
787
788 $this->splash->setTextLoading( sprintf( $bearsamppLang->getValue( Lang::STARTUP_REGISTRY_TEXT ), Registry::APP_BINS_REG_ENTRY ) );
789 $this->splash->incrProgressBar();
790
791 $currentAppBinsRegKey = Util::getAppBinsRegKey();
792 $genAppBinsRegKey = Util::getAppBinsRegKey( false );
793 $this->writeLog( 'Current app bins reg key: ' . $currentAppBinsRegKey );
794 $this->writeLog( 'Gen app bins reg key: ' . $genAppBinsRegKey );
795 if ( $currentAppBinsRegKey != $genAppBinsRegKey ) {
796 if ( !Util::setAppBinsRegKey( $genAppBinsRegKey ) ) {
797 if ( !empty( $this->error ) ) {
798 $this->error .= PHP_EOL . PHP_EOL;
799 }
801 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
802 }
803 else {
804 $this->writeLog( 'Need restart: checkBinsRegKey' );
805 $this->restart = true;
806 }
807 }
808 }
const STARTUP_REGISTRY_ERROR_TEXT
const STARTUP_REGISTRY_TEXT
const APP_BINS_REG_ENTRY
static getAppBinsRegKey($fromRegistry=true)
static setAppBinsRegKey($value)

References $bearsamppLang, Registry\APP_BINS_REG_ENTRY, Util\getAppBinsRegKey(), Util\setAppBinsRegKey(), Lang\STARTUP_REGISTRY_ERROR_TEXT, Lang\STARTUP_REGISTRY_TEXT, and writeLog().

Referenced by processWindow().

◆ checkBrowser()

checkBrowser ( )
private

Checks and sets the default browser configuration.

Definition at line 614 of file class.action.startup.php.

615 {
617
618 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_CHECK_BROWSER_TEXT ) );
619 $this->splash->incrProgressBar();
620 $this->writeLog( 'Check browser' );
621
622 $currentBrowser = $bearsamppConfig->getBrowser();
623 if ( empty( $currentBrowser ) || !file_exists( $currentBrowser ) ) {
625 }
626 }
const CFG_BROWSER
const STARTUP_CHECK_BROWSER_TEXT
static getDefaultBrowser()
global $bearsamppConfig
Definition homepage.php:41

References $bearsamppConfig, $bearsamppLang, Config\CFG_BROWSER, Win32Native\getDefaultBrowser(), Lang\STARTUP_CHECK_BROWSER_TEXT, and writeLog().

Referenced by processWindow().

◆ checkLaunchStartup()

checkLaunchStartup ( )
private

Checks and sets the launch startup configuration.

Definition at line 597 of file class.action.startup.php.

598 {
599 global $bearsamppConfig;
600
601 $this->writeLog( 'Check launch startup' );
602
603 if ( $bearsamppConfig->isLaunchStartup() ) {
605 }
606 else {
608 }
609 }
static disableLaunchStartup()
static enableLaunchStartup()

References $bearsamppConfig, Util\disableLaunchStartup(), Util\enableLaunchStartup(), and writeLog().

Referenced by processWindow().

◆ checkMySQLServiceWithTimeout()

checkMySQLServiceWithTimeout ( $service,
$bin )
private

Specialized method to check MySQL service with timeout protection. MySQL service checks can sometimes hang, so this method provides a safer way to check.

Parameters
object$serviceThe MySQL service object
object$binThe MySQL bin object
Returns
mixed Service info array or false if service not installed or check timed out

Definition at line 1276 of file class.action.startup.php.

1277 {
1278 Log::trace('Starting specialized MySQL service check with timeout protection');
1279
1280 // Set a timeout for the MySQL service check
1281 $serviceCheckStartTime = microtime(true);
1282 $serviceCheckTimeout = 8; // 8 seconds timeout
1283
1284 try {
1285 // Use a non-blocking approach to check service
1286 $serviceInfos = false;
1287
1288 // First check if the service exists in the list
1289 $serviceList = Win32Service::getServices();
1290 if (is_array($serviceList) && isset($serviceList[$service->getName()])) {
1291 Log::trace('MySQL service found in service list, getting details');
1292
1293 // Service exists, now try to get its details with timeout protection
1294 $serviceInfos = $service->infos();
1295
1296 // Check if we've exceeded our timeout
1297 if (microtime(true) - $serviceCheckStartTime > $serviceCheckTimeout) {
1298 Log::trace("MySQL service check timeout exceeded, assuming service needs reinstall");
1299 return false;
1300 }
1301 } else {
1302 Log::trace('MySQL service not found in service list');
1303 return false;
1304 }
1305
1306 return $serviceInfos;
1307 } catch (\Exception $e) {
1308 Log::trace("Exception during MySQL service check: " . $e->getMessage());
1309 return false;
1310 } catch (\Throwable $e) {
1311 Log::trace("Throwable during MySQL service check: " . $e->getMessage());
1312 return false;
1313 }
1314 }

References Log\trace().

Referenced by prepareService().

◆ checkPath()

checkPath ( )
private

Checks the application path and logs the last path content.

Definition at line 673 of file class.action.startup.php.

674 {
676
677 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_CHECK_PATH_TEXT ) );
678 $this->splash->incrProgressBar();
679
680 $this->writeLog( 'Last path: ' . $bearsamppCore->getLastPathContent() );
681 }
const STARTUP_CHECK_PATH_TEXT

References $bearsamppCore, $bearsamppLang, Lang\STARTUP_CHECK_PATH_TEXT, and writeLog().

Referenced by processWindow().

◆ checkPathRegKey()

checkPathRegKey ( )
private

Checks and updates the application path registry key.

Definition at line 751 of file class.action.startup.php.

752 {
753 global $bearsamppRoot, $bearsamppLang, $bearsamppRegistry;
754
755 $this->splash->setTextLoading( sprintf( $bearsamppLang->getValue( Lang::STARTUP_REGISTRY_TEXT ), Registry::APP_PATH_REG_ENTRY ) );
756 $this->splash->incrProgressBar();
757
758 $currentAppPathRegKey = Util::getAppPathRegKey();
759 $genAppPathRegKey = UtilPath::formatWindowsPath( $bearsamppRoot->getRootPath() );
760 $this->writeLog( 'Current app path reg key: ' . $currentAppPathRegKey );
761 $this->writeLog( 'Gen app path reg key: ' . $genAppPathRegKey );
762 if ( $currentAppPathRegKey != $genAppPathRegKey ) {
763 if ( !Util::setAppPathRegKey( $genAppPathRegKey ) ) {
764 if ( !empty( $this->error ) ) {
765 $this->error .= PHP_EOL . PHP_EOL;
766 }
768 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
769 }
770 else {
771 $this->writeLog( 'Need restart: checkPathRegKey' );
772 $this->restart = true;
773 }
774 }
775 }
const APP_PATH_REG_ENTRY
static setAppPathRegKey($value)
static getAppPathRegKey()
static formatWindowsPath($path)

References $bearsamppLang, $bearsamppRoot, Registry\APP_PATH_REG_ENTRY, UtilPath\formatWindowsPath(), Util\getAppPathRegKey(), Util\setAppPathRegKey(), Lang\STARTUP_REGISTRY_ERROR_TEXT, Lang\STARTUP_REGISTRY_TEXT, and writeLog().

Referenced by processWindow().

◆ checkSystemPathRegKey()

checkSystemPathRegKey ( )
private

Checks and updates the system PATH registry key. Ensures the application bins registry entry is at the beginning of the system PATH. Logs the current and new system PATH. Sets an error message if the system PATH update fails. Sets a restart flag if the system PATH is updated.

Definition at line 817 of file class.action.startup.php.

818 {
819 global $bearsamppLang, $bearsamppRegistry;
820
821 $this->splash->setTextLoading( sprintf( $bearsamppLang->getValue( Lang::STARTUP_REGISTRY_TEXT ), Registry::SYSPATH_REG_ENTRY ) );
822 $this->splash->incrProgressBar();
823
824 $currentSysPathRegKey = Util::getSysPathRegKey();
825 $this->writeLog( 'Current system PATH: ' . $currentSysPathRegKey );
826
827 $newSysPathRegKey = str_replace( '%' . Registry::APP_BINS_REG_ENTRY . '%;', '', $currentSysPathRegKey );
828 $newSysPathRegKey = str_replace( '%' . Registry::APP_BINS_REG_ENTRY . '%', '', $newSysPathRegKey );
829 $newSysPathRegKey = '%' . Registry::APP_BINS_REG_ENTRY . '%;' . $newSysPathRegKey;
830 $this->writeLog( 'New system PATH: ' . $newSysPathRegKey );
831
832 if ( $currentSysPathRegKey != $newSysPathRegKey ) {
833 if ( !Util::setSysPathRegKey( $newSysPathRegKey ) ) {
834 if ( !empty( $this->error ) ) {
835 $this->error .= PHP_EOL . PHP_EOL;
836 }
838 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
839 }
840 else {
841 $this->writeLog( 'Need restart: checkSystemPathRegKey' );
842 $this->restart = true;
843 }
844 }
845 else {
846 $this->writeLog( 'Refresh system PATH: ' . $currentSysPathRegKey );
847 Util::setSysPathRegKey( str_replace( '%' . Registry::APP_BINS_REG_ENTRY . '%', '', $currentSysPathRegKey ) );
848 Util::setSysPathRegKey( $currentSysPathRegKey );
849 }
850 }
const SYSPATH_REG_ENTRY
static setSysPathRegKey($value)
static getSysPathRegKey()

References $bearsamppLang, Registry\APP_BINS_REG_ENTRY, Util\getSysPathRegKey(), Util\setSysPathRegKey(), Lang\STARTUP_REGISTRY_ERROR_TEXT, Lang\STARTUP_REGISTRY_TEXT, Registry\SYSPATH_REG_ENTRY, and writeLog().

Referenced by processWindow().

◆ cleanOldBehaviors()

cleanOldBehaviors ( )
private

Cleans old behaviors by removing outdated registry entries.

Definition at line 528 of file class.action.startup.php.

529 {
530 global $bearsamppLang, $bearsamppRegistry;
531
532 $this->writeLog( 'Clean old behaviors' );
533
534 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_CLEAN_OLD_BEHAVIORS_TEXT ) );
535 $this->splash->incrProgressBar();
536
537 // App >= 1.0.13
538 $bearsamppRegistry->deleteValue(
540 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
542 );
543 }
const STARTUP_CLEAN_OLD_BEHAVIORS_TEXT
const HKEY_LOCAL_MACHINE

References $bearsamppLang, APP_TITLE, Registry\HKEY_LOCAL_MACHINE, Lang\STARTUP_CLEAN_OLD_BEHAVIORS_TEXT, and writeLog().

Referenced by processWindow().

◆ cleanTmpFolders()

cleanTmpFolders ( )
private

Cleans temporary folders by removing unnecessary files.

Definition at line 498 of file class.action.startup.php.

499 {
501
502 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_CLEAN_TMP_TEXT ) );
503 $this->splash->incrProgressBar();
504
505 $this->writeLog( 'Clear tmp folders' );
506 Util::clearFolder( $bearsamppRoot->getTmpPath(), array('cachegrind', 'composer', 'openssl', 'mailpit', 'xlight', 'npm-cache', 'pip', 'opcache', '.gitignore') );
507 Util::clearFolder( $bearsamppCore->getTmpPath(), array('.gitignore') );
508
509 // Ensure opcache directory exists for persistent file cache
510 $opcachePath = $bearsamppRoot->getTmpPath() . DIRECTORY_SEPARATOR . 'opcache';
511
512 if (!is_dir($opcachePath)) {
513 $this->writeLog('Creating opcache directory: ' . $opcachePath);
514 if (!@mkdir($opcachePath, 0755, true) && !is_dir($opcachePath)) {
515 $this->writeLog('Failed to create opcache directory: ' . $opcachePath);
516 return;
517 }
518 }
519
520 if (!is_writable($opcachePath)) {
521 $this->writeLog('Opcache directory is not writable: ' . $opcachePath);
522 }
523 }
const STARTUP_CLEAN_TMP_TEXT
static clearFolder($path, $exclude=array())

References $bearsamppCore, $bearsamppLang, $bearsamppRoot, Util\clearFolder(), Lang\STARTUP_CLEAN_TMP_TEXT, and writeLog().

Referenced by processWindow().

◆ createSslCrts()

createSslCrts ( )
private

Creates SSL certificates if they do not already exist. Logs the creation process.

Definition at line 873 of file class.action.startup.php.

874 {
875 global $bearsamppLang, $bearsamppOpenSsl;
876
877 $this->splash->incrProgressBar();
878 if ( !$bearsamppOpenSsl->existsCrt( 'localhost' ) ) {
879 $this->splash->setTextLoading( sprintf( $bearsamppLang->getValue( Lang::STARTUP_GEN_SSL_CRT_TEXT ), 'localhost' ) );
880 $bearsamppOpenSsl->createCrt( 'localhost' );
881 }
882 }
const STARTUP_GEN_SSL_CRT_TEXT

References $bearsamppLang, and Lang\STARTUP_GEN_SSL_CRT_TEXT.

Referenced by processWindow().

◆ installServices()

installServices ( )
private

Installs and starts services for the application. Checks if services are already installed and updates them if necessary. Logs the installation process and any errors encountered.

Uses optimized service checking and starting methods.

Definition at line 892 of file class.action.startup.php.

893 {
895
896 Log::trace('Starting installServices method');
897
898 if (!$this->restart) {
899 Log::trace('Normal startup mode - processing services');
900
901 // Admin check is now performed at the very beginning of processWindow()
902 // No need to check again here
903
904 // Service Installation
906 } else {
907 Log::trace('Restart mode - skipping service installation');
908 $this->splash->incrProgressBar(self::GAUGE_SERVICES * count($bearsamppBins->getServices()));
909 }
910
911 Log::trace('Completed installServices method');
912 }
installServicesSequential($bearsamppBins, $bearsamppLang)

References $bearsamppBins, $bearsamppLang, $bearsamppRoot, installServicesSequential(), and Log\trace().

Referenced by processWindow().

◆ installServicesSequential()

installServicesSequential ( $bearsamppBins,
$bearsamppLang )
private

Service Installation Installs and starts services sequentially with proper progress tracking. Ensures exactly GAUGE_SERVICES (5) progress steps per service.

Parameters
object$bearsamppBinsThe bins object
object$bearsamppLangThe language object

Definition at line 922 of file class.action.startup.php.

923 {
924 Log::trace('Starting sequential service installation');
925 $installStartTime = Util::getMicrotime();
926
927 // Step 1: Check and prepare all services
928 $servicesToStart = [];
929 $serviceErrors = [];
930
931 $totalServiceCount = count($bearsamppBins->getServices());
932 $currentServiceIndex = 0;
933
934 foreach ($bearsamppBins->getServices() as $sName => $service) {
935 $currentServiceIndex++;
936
937 Log::trace('Preparing service: ' . $sName);
938
939 // prepareService() increments 1 step
940 $serviceInfo = $this->prepareService($sName, $service, $bearsamppBins, $bearsamppLang, $currentServiceIndex, $totalServiceCount);
941
942 if ($serviceInfo['restart']) {
943 $this->writeLog('Need restart: installService ' . $serviceInfo['bin']->getName());
944 Log::trace('Restart required for service: ' . $serviceInfo['bin']->getName());
945 $this->restart = true;
946 // prepareService used 1 step, need 4 more to reach GAUGE_SERVICES (5 total)
947 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 1);
948 continue;
949 }
950
951 if (!empty($serviceInfo['error'])) {
952 $serviceErrors[$sName] = $serviceInfo;
953 // prepareService used 1 step, need 4 more to reach GAUGE_SERVICES (5 total)
954 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 1);
955 continue;
956 }
957
958 if ($serviceInfo['needsStart']) {
959 $servicesToStart[$sName] = $serviceInfo;
960 } else {
961 // Service already running or doesn't need to start
962 // prepareService used 1 step, need 4 more to reach GAUGE_SERVICES (5 total)
963 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 1);
964 }
965 }
966
967 // Step 2: Start all services sequentially with progress updates
968 if (!empty($servicesToStart)) {
969 Log::trace('Starting ' . count($servicesToStart) . ' services sequentially');
970
971 $serviceCount = 0;
972 $totalServices = count($servicesToStart);
973
974 foreach ($servicesToStart as $sName => $serviceInfo) {
975 $serviceCount++;
976 $name = $serviceInfo['name'];
977 $service = $serviceInfo['service'];
978
979 // Update splash before starting (1 step - 2nd of 5)
980 $this->splash->setTextLoading('Starting ' . $name . ' (' . $serviceCount . '/' . $totalServices . ')');
981 $this->splash->incrProgressBar();
982
983 Log::trace('Starting service: ' . $sName);
984 $serviceStartTime = Util::getMicrotime();
985
986 // Start the service
987 $success = $service->start();
988
989 $duration = round(Util::getMicrotime() - $serviceStartTime, 3);
990
991 if ($success) {
992 $this->writeLog($name . ' service started in ' . $duration . 's');
993 Log::trace('Service ' . $name . ' started successfully in ' . $duration . ' seconds');
994
995 // Update splash after successful start
996 $this->splash->setTextLoading($name . ' started successfully');
997 } else {
998 $error = $service->getError();
999 if (empty($error)) {
1000 $error = 'Failed to start service';
1001 }
1002
1003 $serviceErrors[$sName] = $serviceInfo;
1004 $serviceErrors[$sName]['error'] = $error;
1005 Log::trace('Service ' . $name . ' failed to start: ' . $error);
1006
1007 // Run syntax check if available
1008 if (!empty($serviceInfo['syntaxCheckCmd'])) {
1009 try {
1010 $cmdSyntaxCheck = $serviceInfo['bin']->getCmdLineOutput($serviceInfo['syntaxCheckCmd']);
1011 if (!$cmdSyntaxCheck['syntaxOk']) {
1012 $serviceErrors[$sName]['error'] .= PHP_EOL . 'Syntax error: ' . $cmdSyntaxCheck['content'];
1013 }
1014 } catch (\Exception $e) {
1015 // Ignore syntax check errors
1016 }
1017 }
1018 }
1019
1020 // Complete remaining steps: prepareService=1, pre-start=1, now add 3 more = 5 total
1021 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 2);
1022 }
1023 }
1024
1025 // Step 3: Report any errors
1026 foreach ($serviceErrors as $sName => $serviceInfo) {
1027 if (!empty($serviceInfo['error'])) {
1028 Log::trace('Service error occurred for ' . $sName . ': ' . $serviceInfo['error']);
1029 if (!empty($this->error)) {
1030 $this->error .= PHP_EOL . PHP_EOL;
1031 }
1032 $this->error .= sprintf($bearsamppLang->getValue(Lang::STARTUP_SERVICE_ERROR), $serviceInfo['name']) . PHP_EOL . $serviceInfo['error'];
1033 }
1034 }
1035
1036 $installDuration = round(Util::getMicrotime() - $installStartTime, 3);
1037 $this->writeLog('Service installation completed in ' . $installDuration . 's');
1038 Log::trace('Service installation completed in ' . $installDuration . ' seconds');
1039 }
prepareService($sName, $service, $bearsamppBins, $bearsamppLang, $currentIndex=0, $totalCount=0)
const STARTUP_SERVICE_ERROR

References $bearsamppBins, $bearsamppLang, $error, Util\getMicrotime(), prepareService(), Lang\STARTUP_SERVICE_ERROR, Log\trace(), and writeLog().

Referenced by installServices().

◆ killOldInstances()

killOldInstances ( )
private

Kills old instances of Bearsampp processes.

Definition at line 548 of file class.action.startup.php.

549 {
550 global $bearsamppLang;
551
552 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_KILL_OLD_PROCS_TEXT ) );
553 $this->splash->incrProgressBar();
554
555 // Stop services
556 /*foreach ($bearsamppBins->getServices() as $sName => $service) {
557 $serviceInfos = $service->infos();
558 if ($serviceInfos === false) {
559 continue;
560 }
561 $service->stop();
562 }*/
563
564 // Stop third party procs
565 $procsKilled = Win32Ps::killBins();
566 if ( !empty( $procsKilled ) ) {
567 $this->writeLog( 'Procs killed:' );
568 $procsKilledSort = array();
569 foreach ( $procsKilled as $proc ) {
571 $procsKilledSort[] = '-> ' . basename( $unixExePath ) . ' (PID ' . $proc[Win32Ps::PROCESS_ID] . ') in ' . $unixExePath;
572 }
573 sort( $procsKilledSort );
574 foreach ( $procsKilledSort as $proc ) {
575 $this->writeLog( $proc );
576 }
577 }
578 }
$proc
Definition ajax.php:61
const STARTUP_KILL_OLD_PROCS_TEXT
static formatUnixPath($path)
static killBins($refreshProcs=false)
const EXECUTABLE_PATH
const PROCESS_ID

References $bearsamppLang, $proc, Win32Ps\EXECUTABLE_PATH, UtilPath\formatUnixPath(), Win32Ps\killBins(), Win32Ps\PROCESS_ID, Lang\STARTUP_KILL_OLD_PROCS_TEXT, and writeLog().

Referenced by processWindow().

◆ prepareService()

prepareService ( $sName,
$service,
$bearsamppBins,
$bearsamppLang,
$currentIndex = 0,
$totalCount = 0 )
private

Prepares a service for startup (check, install if needed, but don't start yet)

Parameters
string$sNameService name
object$serviceService object
object$bearsamppBinsBins object
object$bearsamppLangLanguage object
int$currentIndexCurrent service index
int$totalCountTotal service count
Returns
array Service information array

Definition at line 1052 of file class.action.startup.php.

1053 {
1054 $serviceInfo = [
1055 'sName' => $sName,
1056 'service' => $service,
1057 'bin' => null,
1058 'name' => '',
1059 'port' => 0,
1060 'syntaxCheckCmd' => null,
1061 'error' => '',
1062 'restart' => false,
1063 'needsStart' => false,
1064 'startTime' => Util::getMicrotime()
1065 ];
1066
1067 // Identify service type and get bin
1068 $syntaxCheckCmd = null;
1069 $bin = null;
1070 $port = 0;
1071
1072 if ($sName == BinMailpit::SERVICE_NAME) {
1073 $bin = $bearsamppBins->getMailpit();
1074 $port = $bearsamppBins->getMailpit()->getSmtpPort();
1075 } elseif ($sName == BinMemcached::SERVICE_NAME) {
1076 $bin = $bearsamppBins->getMemcached();
1077 $port = $bearsamppBins->getMemcached()->getPort();
1078 } elseif ($sName == BinApache::SERVICE_NAME) {
1079 $bin = $bearsamppBins->getApache();
1080 $port = $bearsamppBins->getApache()->getPort();
1081 $syntaxCheckCmd = BinApache::CMD_SYNTAX_CHECK;
1082 } elseif ($sName == BinMysql::SERVICE_NAME) {
1083 $bin = $bearsamppBins->getMysql();
1084 $port = $bearsamppBins->getMysql()->getPort();
1085 $syntaxCheckCmd = BinMysql::CMD_SYNTAX_CHECK;
1086
1087 // Pre-initialize MySQL data if needed
1088 if (!file_exists($bin->getDataDir()) || count(glob($bin->getDataDir() . '/*')) === 0) {
1089 Log::trace('Pre-initializing MySQL data directory');
1090 $bin->initData();
1091 }
1092 } elseif ($sName == BinMariadb::SERVICE_NAME) {
1093 $bin = $bearsamppBins->getMariadb();
1094 $port = $bearsamppBins->getMariadb()->getPort();
1095 $syntaxCheckCmd = BinMariadb::CMD_SYNTAX_CHECK;
1096 } elseif ($sName == BinPostgresql::SERVICE_NAME) {
1097 $bin = $bearsamppBins->getPostgresql();
1098 $port = $bearsamppBins->getPostgresql()->getPort();
1099 } elseif ($sName == BinXlight::SERVICE_NAME) {
1100 $bin = $bearsamppBins->getXlight();
1101 $port = $bearsamppBins->getXlight()->getPort();
1102 }
1103
1104 $name = $bin->getName() . ' ' . $bin->getVersion() . ' (' . $service->getName() . ')';
1105
1106 $serviceInfo['bin'] = $bin;
1107 $serviceInfo['name'] = $name;
1108 $serviceInfo['port'] = $port;
1109 $serviceInfo['syntaxCheckCmd'] = $syntaxCheckCmd;
1110
1111 // Update splash with current service being checked (1 step)
1112 if ($currentIndex > 0 && $totalCount > 0) {
1113 $this->splash->setTextLoading('Checking ' . $bin->getName() . ' service (' . $currentIndex . '/' . $totalCount . ')');
1114 }
1115 $this->splash->incrProgressBar();
1116
1117 // Check if service is already installed
1118 $serviceAlreadyInstalled = false;
1119 $serviceToRemove = false;
1120
1121 if ($sName == BinApache::SERVICE_NAME) {
1122 $serviceInfos = $this->checkApacheServiceWithTimeout($service);
1123 } else if ($sName == BinMysql::SERVICE_NAME) {
1124 $serviceInfos = $this->checkMySQLServiceWithTimeout($service, $bin);
1125 if ($serviceInfos === false && $service->isInstalled()) {
1126 Log::trace('MySQL service appears to be hanging, forcing restart');
1127 Win32Ps::killBins(['mysqld.exe']);
1128 $service->delete();
1129 $serviceToRemove = true;
1130 }
1131 } else {
1132 try {
1133 $serviceInfos = $service->infos();
1134 } catch (\Exception $e) {
1135 Log::trace("Exception during service check: " . $e->getMessage());
1136 $serviceInfos = false;
1137 } catch (\Throwable $e) {
1138 Log::trace("Throwable during service check: " . $e->getMessage());
1139 $serviceInfos = false;
1140 }
1141 }
1142
1143 if ($serviceInfos !== false) {
1144 $serviceAlreadyInstalled = true;
1145 $this->writeLog($name . ' service already installed');
1146
1147 // Check if service needs to be removed and reinstalled
1148 if ($sName == BinPostgresql::SERVICE_NAME) {
1149 $serviceGenPathName = trim(str_replace('"', '', $service->getBinPath()));
1150 $installedPathParts = explode(' ', $serviceInfos[Win32Service::VBS_PATH_NAME], 2);
1151 $serviceVbsPathName = trim(str_replace('"', '', $installedPathParts[0]));
1152 } else {
1153 $serviceGenPathName = trim(str_replace('"', '', $service->getBinPath() . ($service->getParams() ? ' ' . $service->getParams() : '')));
1154 $serviceVbsPathName = trim(str_replace('"', '', $serviceInfos[Win32Service::VBS_PATH_NAME]));
1155 }
1156
1157 $normalizedGenPath = preg_replace('/\s+/', ' ', $serviceGenPathName);
1158 $normalizedVbsPath = preg_replace('/\s+/', ' ', $serviceVbsPathName);
1159
1160 if ($normalizedGenPath !== $normalizedVbsPath && $serviceGenPathName != $serviceVbsPathName) {
1161 $serviceToRemove = true;
1162 $this->writeLog($name . ' service has to be removed');
1163 }
1164 }
1165
1166 // Remove service if needed (no progress increment - part of check phase)
1167 if ($serviceToRemove) {
1168 if (!$service->delete()) {
1169 $serviceInfo['restart'] = true;
1170 return $serviceInfo;
1171 }
1172 }
1173
1174 // Check port availability (no progress increment - part of check phase)
1175 $isPortInUse = Util::isPortInUse($port);
1176 if ($isPortInUse !== false) {
1177 // Port is in use - check if it's our service that's already running
1178 if ($service->isRunning()) {
1179 // Service is already running and owns the port - this is OK
1180 $this->writeLog($name . ' service already running on port ' . $port);
1181 Log::trace('Service ' . $name . ' already running - no need to start');
1182 $serviceInfo['needsStart'] = false;
1183 return $serviceInfo;
1184 }
1185
1186 // Port is in use by something else - this is an error
1187 $serviceInfo['error'] = sprintf($bearsamppLang->getValue(Lang::STARTUP_SERVICE_PORT_ERROR), $port, $isPortInUse);
1188 return $serviceInfo;
1189 }
1190
1191 // Install service if needed (no progress increment - part of check phase)
1192 if (!$serviceAlreadyInstalled || $serviceToRemove) {
1193 if (!$service->create()) {
1194 $serviceInfo['error'] = sprintf($bearsamppLang->getValue(Lang::STARTUP_SERVICE_CREATE_ERROR), $service->getError());
1195 return $serviceInfo;
1196 }
1197 }
1198
1199 $serviceInfo['needsStart'] = true;
1200 return $serviceInfo;
1201 }
$port
checkMySQLServiceWithTimeout($service, $bin)
checkApacheServiceWithTimeout($service)
const CMD_SYNTAX_CHECK
const SERVICE_NAME
const CMD_SYNTAX_CHECK
const STARTUP_SERVICE_CREATE_ERROR
const STARTUP_SERVICE_PORT_ERROR
static isPortInUse($port)

References $bearsamppBins, $bearsamppLang, $port, checkApacheServiceWithTimeout(), checkMySQLServiceWithTimeout(), BinApache\CMD_SYNTAX_CHECK, BinMariadb\CMD_SYNTAX_CHECK, BinMysql\CMD_SYNTAX_CHECK, Util\getMicrotime(), Util\isPortInUse(), Win32Ps\killBins(), BinApache\SERVICE_NAME, BinMailpit\SERVICE_NAME, BinMariadb\SERVICE_NAME, BinMemcached\SERVICE_NAME, BinMysql\SERVICE_NAME, BinPostgresql\SERVICE_NAME, BinXlight\SERVICE_NAME, Lang\STARTUP_SERVICE_CREATE_ERROR, Lang\STARTUP_SERVICE_PORT_ERROR, Log\trace(), Win32Service\VBS_PATH_NAME, and writeLog().

Referenced by installServicesSequential().

◆ processWindow()

processWindow ( $window,
$id,
$ctrl,
$param1,
$param2 )

Processes the main window events during startup.

Parameters
mixed$windowThe window handle.
int$idThe event ID.
mixed$ctrlThe control that triggered the event.
mixed$param1Additional parameter 1.
mixed$param2Additional parameter 2.

Definition at line 77 of file class.action.startup.php.

78 {
79 global $bearsamppRoot, $bearsamppCore, $bearsamppLang, $bearsamppBins, $bearsamppTools, $bearsamppApps, $bearsamppWinbinder;
80
81 Log::trace('Starting processWindow method');
82
83 // Admin check is now performed in the constructor before anything else
84 // No need to check again here
85
86 // Rotation logs
87 Log::trace('Performing log rotation');
88 $this->rotationLogs();
89
90 // Clean
91 Log::trace('Starting cleanup operations');
92 $this->cleanTmpFolders();
93 $this->cleanOldBehaviors();
94
95 // List procs
96 Log::trace('Listing running processes');
97 if ($bearsamppRoot->getProcs() !== false) {
98 $this->writeLog('List procs:');
99 $listProcs = array();
100 foreach ($bearsamppRoot->getProcs() as $proc) {
102 $listProcs[] = '-> ' . basename($unixExePath) . ' (PID ' . $proc[Win32Ps::PROCESS_ID] . ') in ' . $unixExePath;
103 }
104 sort($listProcs);
105 foreach ($listProcs as $proc) {
106 $this->writeLog($proc);
107 }
108 Log::trace('Found ' . count($listProcs) . ' running processes');
109 } else {
110 Log::trace('No processes found or unable to retrieve process list');
111 }
112
113 // List modules
114 Log::trace('Listing bins modules');
115 $this->writeLog('List bins modules:');
116 foreach ($bearsamppBins->getAll() as $module) {
117 if (!$module->isEnable()) {
118 $this->writeLog('-> ' . $module->getName() . ': ' . $bearsamppLang->getValue(Lang::DISABLED));
119 Log::trace('Bin module ' . $module->getName() . ' is disabled');
120 } else {
121 $this->writeLog('-> ' . $module->getName() . ': ' . $module->getVersion() . ' (' . $module->getRelease() . ')');
122 Log::trace('Bin module ' . $module->getName() . ': ' . $module->getVersion() . ' (' . $module->getRelease() . ')');
123 }
124 }
125
126 Log::trace('Listing tools modules');
127 $this->writeLog('List tools modules:');
128 foreach ($bearsamppTools->getAll() as $module) {
129 if (!$module->isEnable()) {
130 $this->writeLog('-> ' . $module->getName() . ': ' . $bearsamppLang->getValue(Lang::DISABLED));
131 Log::trace('Tool module ' . $module->getName() . ' is disabled');
132 } else {
133 $this->writeLog('-> ' . $module->getName() . ': ' . $module->getVersion() . ' (' . $module->getRelease() . ')');
134 Log::trace('Tool module ' . $module->getName() . ': ' . $module->getVersion() . ' (' . $module->getRelease() . ')');
135 }
136 }
137
138 Log::trace('Listing apps modules');
139 $this->writeLog('List apps modules:');
140 foreach ($bearsamppApps->getAll() as $module) {
141 if (!$module->isEnable()) {
142 $this->writeLog('-> ' . $module->getName() . ': ' . $bearsamppLang->getValue(Lang::DISABLED));
143 Log::trace('App module ' . $module->getName() . ' is disabled');
144 } else {
145 $this->writeLog('-> ' . $module->getName() . ': ' . $module->getVersion() . ' (' . $module->getRelease() . ')');
146 Log::trace('App module ' . $module->getName() . ': ' . $module->getVersion() . ' (' . $module->getRelease() . ')');
147 }
148 }
149
150 // Kill old instances
151 Log::trace('Killing old instances');
152 $this->killOldInstances();
153
154 // Prepare app
155 Log::trace('Preparing application - refreshing hostname');
156 $this->refreshHostname();
157
158 Log::trace('Checking launch startup settings');
159 $this->checkLaunchStartup();
160
161 Log::trace('Checking browser configuration');
162 $this->checkBrowser();
163
164 Log::trace('Gathering system information');
165 $this->sysInfos();
166
167 Log::trace('Refreshing aliases');
168 $this->refreshAliases();
169
170 Log::trace('Refreshing virtual hosts');
171 $this->refreshVhosts();
172
173 // Check app path
174 Log::trace('Checking application path');
175 $this->checkPath();
176
177 Log::trace('Scanning folders');
178 $this->scanFolders();
179
180 Log::trace('Changing paths in files');
181 $this->changePath();
182
183 Log::trace('Saving current path');
184 $this->savePath();
185
186 // Check BEARSAMPP_PATH, BEARSAMPP_BINS and System Path reg keys
187 Log::trace('Checking PATH registry key');
188 $this->checkPathRegKey();
189
190 Log::trace('Checking BINS registry key');
191 $this->checkBinsRegKey();
192
193 Log::trace('Checking System PATH registry key');
194 $this->checkSystemPathRegKey();
195
196 // Update config
197 Log::trace('Updating configuration');
198 $this->updateConfig();
199
200 // Create SSL certificates
201 Log::trace('Creating SSL certificates');
202 $this->createSslCrts();
203
204 // Install
205 Log::trace('Installing services');
206 $this->installServices();
207
208 // Actions if everything OK
209 if (!$this->restart && empty($this->error)) {
210 Log::trace('Startup completed successfully - refreshing Git repositories');
211 $this->refreshGitRepos();
212 $startupTime = round(Util::getMicrotime() - $this->startTime, 3);
213 $this->writeLog('Started in ' . $startupTime . 's');
214 Log::trace('Application started successfully in ' . $startupTime . ' seconds');
215
216 // Log total startup time in VERBOSE_TRACE mode (mode 3)
217 global $bearsamppConfig;
218 if ($bearsamppConfig->getLogsVerbose() == Config::VERBOSE_TRACE) {
219 $minutes = floor($startupTime / 60); // floor() returns int-compatible value
220 $seconds = fmod($startupTime, 60);
221 $formattedTime = sprintf('%d:%05.2f', $minutes, $seconds);
222 Log::trace('=== TOTAL STARTUP TIME: ' . $formattedTime . ' ===');
223 }
224 } else {
225 Log::trace('Startup issues detected - incrementing progress bar');
226 $this->splash->incrProgressBar(2);
227 }
228
229 if ($this->restart) {
230 Log::trace('Restart required - preparing to restart application');
231 $this->writeLog(APP_TITLE . ' has to be restarted');
232 $this->splash->setTextLoading(
233 sprintf(
235 APP_TITLE . ' ' . $bearsamppCore->getAppVersion()
236 )
237 );
238
239 Log::trace('Deleting all services before restart');
240 foreach ($bearsamppBins->getServices() as $sName => $service) {
241 Log::trace('Deleting service: ' . $sName);
242 $service->delete();
243 }
244
245 Log::trace('Setting execution action to RESTART');
247 }
248
249 if (!empty($this->error)) {
250 Log::trace('Errors occurred during startup: ' . $this->error);
251 $this->writeLog('Error: ' . $this->error);
252 $bearsamppWinbinder->messageBoxError($this->error, $bearsamppLang->getValue(Lang::STARTUP_ERROR_TITLE));
253 }
254
255 Log::trace('Starting loading screen');
256 // Moved Util::startLoading() to after splash window destruction to prevent double progress bars
257
258 // Give the loading window time to initialize before we terminate this process
259 Log::trace('Waiting for loading window to initialize');
260 usleep(500000); // 500ms delay to allow loading window to start
261
262 Log::trace('Loading process started');
263
264 // Closing cli to finish startup
265 Log::trace('Finishing startup process');
266
267 // Safely reset WinBinder and destroy the splash window
268 $bearsamppWinbinder->destroyWindow($window);
269 $bearsamppWinbinder->reset();
270
271 // Start loading screen AFTER splash window is destroyed to prevent double progress bars
273
274 // Exit this startup process cleanly - the loading window will continue running
275 Log::trace('Exiting startup process cleanly');
276 exit(0);
277
278 }
const VERBOSE_TRACE
const DISABLED
const STARTUP_PREPARE_RESTART_TEXT
const STARTUP_ERROR_TITLE
static startLoading()

References $bearsamppBins, $bearsamppConfig, $bearsamppCore, $bearsamppLang, $bearsamppRoot, $proc, APP_TITLE, changePath(), checkBinsRegKey(), checkBrowser(), checkLaunchStartup(), checkPath(), checkPathRegKey(), checkSystemPathRegKey(), cleanOldBehaviors(), cleanTmpFolders(), createSslCrts(), Lang\DISABLED, Win32Ps\EXECUTABLE_PATH, exit, UtilPath\formatUnixPath(), Util\getMicrotime(), installServices(), killOldInstances(), Win32Ps\PROCESS_ID, refreshAliases(), refreshGitRepos(), refreshHostname(), refreshVhosts(), ActionExec\RESTART, rotationLogs(), savePath(), scanFolders(), Util\startLoading(), Lang\STARTUP_ERROR_TITLE, Lang\STARTUP_PREPARE_RESTART_TEXT, sysInfos(), Log\trace(), updateConfig(), Config\VERBOSE_TRACE, and writeLog().

◆ refreshAliases()

refreshAliases ( )
private

Refreshes the aliases in the Apache configuration.

Definition at line 645 of file class.action.startup.php.

646 {
648
649 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_REFRESH_ALIAS_TEXT ) );
650 $this->splash->incrProgressBar();
651 $this->writeLog( 'Refresh aliases' );
652
653 $bearsamppBins->getApache()->refreshAlias( $bearsamppConfig->isOnline() );
654 }
const STARTUP_REFRESH_ALIAS_TEXT

References $bearsamppBins, $bearsamppConfig, $bearsamppLang, Lang\STARTUP_REFRESH_ALIAS_TEXT, and writeLog().

Referenced by processWindow().

◆ refreshGitRepos()

refreshGitRepos ( )
private

Refreshes Git repositories if the scan on startup is enabled. Logs the number of repositories found.

Definition at line 1207 of file class.action.startup.php.

1208 {
1209 global $bearsamppLang, $bearsamppTools;
1210
1211 $this->splash->incrProgressBar();
1212 if ( $bearsamppTools->getGit()->isScanStartup() ) {
1213 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_REFRESH_GIT_REPOS_TEXT ) );
1214
1215 $repos = $bearsamppTools->getGit()->findRepos( false );
1216 $this->writeLog( 'Update GIT repos: ' . count( $repos ) . ' found' );
1217 }
1218 }
const STARTUP_REFRESH_GIT_REPOS_TEXT

References $bearsamppLang, Lang\STARTUP_REFRESH_GIT_REPOS_TEXT, and writeLog().

Referenced by processWindow().

◆ refreshHostname()

refreshHostname ( )
private

Refreshes the hostname in the configuration.

Definition at line 583 of file class.action.startup.php.

584 {
586
587 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_REFRESH_HOSTNAME_TEXT ) );
588 $this->splash->incrProgressBar();
589 $this->writeLog( 'Refresh hostname' );
590
591 $bearsamppConfig->replace( Config::CFG_HOSTNAME, gethostname() );
592 }
const CFG_HOSTNAME
const STARTUP_REFRESH_HOSTNAME_TEXT

References $bearsamppConfig, $bearsamppLang, Config\CFG_HOSTNAME, Lang\STARTUP_REFRESH_HOSTNAME_TEXT, and writeLog().

Referenced by processWindow().

◆ refreshVhosts()

refreshVhosts ( )
private

Refreshes the virtual hosts in the Apache configuration.

Definition at line 659 of file class.action.startup.php.

660 {
662
663 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_REFRESH_VHOSTS_TEXT ) );
664 $this->splash->incrProgressBar();
665 $this->writeLog( 'Refresh vhosts' );
666
667 $bearsamppBins->getApache()->refreshVhosts( $bearsamppConfig->isOnline() );
668 }
const STARTUP_REFRESH_VHOSTS_TEXT

References $bearsamppBins, $bearsamppConfig, $bearsamppLang, Lang\STARTUP_REFRESH_VHOSTS_TEXT, and writeLog().

Referenced by processWindow().

◆ rotationLogs()

rotationLogs ( )
private

Rotates the logs by archiving old logs and purging old archives. Enhanced with file lock checking to prevent permission denied errors.

Definition at line 284 of file class.action.startup.php.

285 {
287
288 Log::trace("Starting log rotation process");
289 $this->splash->setTextLoading($bearsamppLang->getValue(Lang::STARTUP_ROTATION_LOGS_TEXT));
290 $this->splash->incrProgressBar();
291
292 $archivesPath = $bearsamppRoot->getLogsPath() . '/archives';
293 if (!is_dir($archivesPath)) {
294 Log::trace("Creating archives directory: " . $archivesPath);
295 mkdir($archivesPath, 0777, true);
296 return;
297 }
298
299 $date = date('Y-m-d-His', time());
300 $archiveLogsPath = $archivesPath . '/' . $date;
301 $archiveScriptsPath = $archiveLogsPath . '/scripts';
302
303 // Create archive folders
304 Log::trace("Creating archive directories for current rotation");
305 if (!is_dir($archiveLogsPath)) {
306 Log::trace("Creating logs archive directory: " . $archiveLogsPath);
307 mkdir($archiveLogsPath, 0777, true);
308 } else {
309 Log::trace("Logs archive directory already exists: " . $archiveLogsPath);
310 }
311
312 if (!is_dir($archiveScriptsPath)) {
313 Log::trace("Creating scripts archive directory: " . $archiveScriptsPath);
314 mkdir($archiveScriptsPath, 0777, true);
315 } else {
316 Log::trace("Scripts archive directory already exists: " . $archiveScriptsPath);
317 }
318
319 // Count archives
320 Log::trace("Counting existing archives");
321 $archives = array();
322 $handle = @opendir($archivesPath);
323 if (!$handle) {
324 Log::trace("Failed to open archives directory: " . $archivesPath);
325 return;
326 }
327
328 while (false !== ($file = readdir($handle))) {
329 if ($file == '.' || $file == '..') {
330 continue;
331 }
332 $archives[] = $archivesPath . '/' . $file;
333 }
334 closedir($handle);
335 sort($archives);
336 Log::trace("Found " . count($archives) . " existing archives");
337
338 // Remove old archives
339 if (count($archives) > $bearsamppConfig->getMaxLogsArchives()) {
340 $total = count($archives) - $bearsamppConfig->getMaxLogsArchives();
341 Log::trace("Removing " . $total . " old archives");
342 for ($i = 0; $i < $total; $i++) {
343 Log::trace("Deleting old archive: " . $archives[$i]);
344 Util::deleteFolder($archives[$i]);
345 }
346 }
347
348 // Helper function to check if a file is locked
349 $isFileLocked = function($filePath) {
350 if (!file_exists($filePath)) {
351 return false;
352 }
353
354 $handle = @fopen($filePath, 'r+');
355 if ($handle === false) {
356 Log::trace("File appears to be locked: " . $filePath);
357 return true; // File is locked
358 }
359
360 fclose($handle);
361 return false; // File is not locked
362 };
363
364 // Logs
365 Log::trace("Archiving log files");
366 $srcPath = $bearsamppRoot->getLogsPath();
367 $handle = @opendir($srcPath);
368 if (!$handle) {
369 Log::trace("Failed to open logs directory: " . $srcPath);
370 return;
371 }
372
373 $logsCopied = 0;
374 $logsSkipped = 0;
375
376 while (false !== ($file = readdir($handle))) {
377 if ($file == '.' || $file == '..' || is_dir($srcPath . '/' . $file)) {
378 continue;
379 }
380
381 $sourceFile = $srcPath . '/' . $file;
382 $destFile = $archiveLogsPath . '/' . $file;
383
384 // Check if file is locked before attempting to copy
385 if ($isFileLocked($sourceFile)) {
386 Log::trace("Skipping locked log file: " . $file);
387 $logsSkipped++;
388 continue;
389 }
390
391 try {
392 if (copy($sourceFile, $destFile)) {
393 $logsCopied++;
394 Log::trace("Archived log file: " . $file);
395 } else {
396 $logsSkipped++;
397 Log::trace("Failed to copy log file: " . $file);
398 }
399 } catch (Exception $e) {
400 $logsSkipped++;
401 Log::trace("Exception copying log file " . $file . ": " . $e->getMessage());
402 }
403 }
404 closedir($handle);
405 Log::trace("Logs archived: " . $logsCopied . " copied, " . $logsSkipped . " skipped");
406
407 // Scripts
408 Log::trace("Archiving script files");
409 $srcPath = $bearsamppCore->getTmpPath();
410 $handle = @opendir($srcPath);
411 if (!$handle) {
412 Log::trace("Failed to open tmp directory: " . $srcPath);
413 return;
414 }
415
416 $scriptsCopied = 0;
417 $scriptsSkipped = 0;
418
419 while (false !== ($file = readdir($handle))) {
420 if ($file == '.' || $file == '..' || is_dir($srcPath . '/' . $file)) {
421 continue;
422 }
423
424 $sourceFile = $srcPath . '/' . $file;
425 $destFile = $archiveScriptsPath . '/' . $file;
426
427 // Check if file is locked before attempting to copy
428 if ($isFileLocked($sourceFile)) {
429 Log::trace("Skipping locked script file: " . $file);
430 $scriptsSkipped++;
431 continue;
432 }
433
434 try {
435 if (copy($sourceFile, $destFile)) {
436 $scriptsCopied++;
437 Log::trace("Archived script file: " . $file);
438 } else {
439 $scriptsSkipped++;
440 Log::trace("Failed to copy script file: " . $file);
441 }
442 } catch (Exception $e) {
443 $scriptsSkipped++;
444 Log::trace("Exception copying script file " . $file . ": " . $e->getMessage());
445 }
446 }
447 closedir($handle);
448 Log::trace("Scripts archived: " . $scriptsCopied . " copied, " . $scriptsSkipped . " skipped");
449
450 // Purge logs - only delete files that aren't locked
451 Log::trace("Purging log files");
452 $logsPath = $bearsamppRoot->getLogsPath();
453 $handle = @opendir($logsPath);
454 if (!$handle) {
455 Log::trace("Failed to open logs directory for purging: " . $logsPath);
456 return;
457 }
458
459 $logsDeleted = 0;
460 $logsPurgeSkipped = 0;
461
462 while (false !== ($file = readdir($handle))) {
463 if ($file == '.' || $file == '..' || $file == 'archives' || $file == '.gitignore' || is_dir($logsPath . '/' . $file)) {
464 continue;
465 }
466
467 $filePath = $logsPath . '/' . $file;
468
469 // Check if file is locked before attempting to delete
470 if ($isFileLocked($filePath)) {
471 Log::trace("Skipping locked log file during purge: " . $file);
472 $logsPurgeSkipped++;
473 continue;
474 }
475
476 try {
477 if (file_exists($filePath) && unlink($filePath)) {
478 $logsDeleted++;
479 Log::trace("Purged log file: " . $file);
480 } else {
481 $logsPurgeSkipped++;
482 Log::trace("Failed to purge log file: " . $file);
483 }
484 } catch (Exception $e) {
485 $logsPurgeSkipped++;
486 Log::trace("Exception purging log file " . $file . ": " . $e->getMessage());
487 }
488 }
489 closedir($handle);
490 Log::trace("Logs purged: " . $logsDeleted . " deleted, " . $logsPurgeSkipped . " skipped");
491
492 Log::trace("Log rotation completed");
493 }
const STARTUP_ROTATION_LOGS_TEXT
static deleteFolder($path)

References $bearsamppBins, $bearsamppConfig, $bearsamppCore, $bearsamppLang, $bearsamppRoot, Util\deleteFolder(), Lang\STARTUP_ROTATION_LOGS_TEXT, and Log\trace().

Referenced by processWindow().

◆ savePath()

savePath ( )
private

Saves the current application path.

Definition at line 740 of file class.action.startup.php.

741 {
742 global $bearsamppCore;
743
744 file_put_contents( $bearsamppCore->getLastPath(), $this->rootPath );
745 $this->writeLog( 'Save current path: ' . $this->rootPath );
746 }

References $bearsamppCore, and writeLog().

Referenced by processWindow().

◆ scanFolders()

scanFolders ( )
private

Scans folders and logs the number of files to scan. Performance optimization: Skips expensive file scan when path hasn't changed. This saves 3-8 seconds on typical startups (95% of cases).

Definition at line 688 of file class.action.startup.php.

689 {
691
692 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_SCAN_FOLDERS_TEXT ) );
693 $this->splash->incrProgressBar();
694
695 $lastPath = $bearsamppCore->getLastPathContent();
696 $currentPath = $this->rootPath;
697
698 // Performance optimization: Skip scan if path hasn't changed
699 if ($lastPath === $currentPath) {
700 Log::debug('Path unchanged, skipping file scan (performance optimization)');
701 Log::trace('Last path: "' . $lastPath . '" matches current path: "' . $currentPath . '"');
702 $this->filesToScan = [];
703 $this->writeLog('Files to scan: 0 (path unchanged - scan skipped)');
704
705 // Log performance benefit
706 $this->writeLog('Performance: File scan skipped, saving 3-8 seconds');
707 return;
708 }
709
710 // Path changed, perform full scan
711 Log::debug('Path changed, performing full file scan');
712 Log::trace('Last path: "' . $lastPath . '" differs from current path: "' . $currentPath . '"');
713 $this->writeLog('Path changed detected - performing full scan');
714
715 $scanStartTime = Util::getMicrotime();
716 $this->filesToScan = Util::getFilesToScan();
717 $scanDuration = round(Util::getMicrotime() - $scanStartTime, 3);
718
719 $this->writeLog('Files to scan: ' . count($this->filesToScan) . ' (scanned in ' . $scanDuration . 's)');
720 }
const STARTUP_SCAN_FOLDERS_TEXT
static debug($data, $file=null)
static getFilesToScan($path=null, $useCache=true, $forceRefresh=false)

References $bearsamppCore, $bearsamppLang, $rootPath, Log\debug(), Util\getFilesToScan(), Util\getMicrotime(), Lang\STARTUP_SCAN_FOLDERS_TEXT, Log\trace(), and writeLog().

Referenced by processWindow().

◆ sysInfos()

sysInfos ( )
private

Logs system information.

Definition at line 631 of file class.action.startup.php.

632 {
633 global $bearsamppLang;
634
635 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_SYS_INFOS ) );
636 $this->splash->incrProgressBar();
637
638 $os = Batch::getOsInfo();
639 $this->writeLog( sprintf( 'OS: %s', $os ) );
640 }
static getOsInfo()
const STARTUP_SYS_INFOS

References $bearsamppLang, Batch\getOsInfo(), Lang\STARTUP_SYS_INFOS, and writeLog().

Referenced by processWindow().

◆ updateConfig()

updateConfig ( )
private

Updates the configuration for bins, tools, and apps. Logs the update process.

Definition at line 856 of file class.action.startup.php.

857 {
858 global $bearsamppLang, $bearsamppBins, $bearsamppTools, $bearsamppApps;
859
860 $this->splash->setTextLoading( $bearsamppLang->getValue( Lang::STARTUP_UPDATE_CONFIG_TEXT ) );
861 $this->splash->incrProgressBar();
862 $this->writeLog( 'Update config' );
863
864 $bearsamppBins->update();
865 $bearsamppTools->update();
866 $bearsamppApps->update();
867 }
const STARTUP_UPDATE_CONFIG_TEXT

References $bearsamppBins, $bearsamppLang, Lang\STARTUP_UPDATE_CONFIG_TEXT, and writeLog().

Referenced by processWindow().

◆ writeLog()

writeLog ( $log)
private

Field Documentation

◆ $error

$error
private

Definition at line 21 of file class.action.startup.php.

Referenced by installServicesSequential().

◆ $filesToScan

$filesToScan
private

Definition at line 24 of file class.action.startup.php.

◆ $restart

$restart
private

Definition at line 19 of file class.action.startup.php.

◆ $rootPath

$rootPath
private

Definition at line 23 of file class.action.startup.php.

Referenced by scanFolders().

◆ $splash

$splash
private

Definition at line 18 of file class.action.startup.php.

◆ $startTime

$startTime
private

Definition at line 20 of file class.action.startup.php.

Referenced by checkApacheServiceWithTimeout().

◆ GAUGE_OTHERS

const GAUGE_OTHERS = 19

Definition at line 27 of file class.action.startup.php.

◆ GAUGE_SERVICES

const GAUGE_SERVICES = 5

Definition at line 26 of file class.action.startup.php.


The documentation for this class was generated from the following file: