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

Public Member Functions

 __construct ($name)
 create ()
 delete ()
 ensureReset ()
 fastServiceCheck ()
 getBinPath ()
 getDisplayName ()
 getError ()
 getErrorControl ()
 getLatestError ()
 getLatestStatus ()
 getName ()
 getNssm ()
 getParams ()
 getStartType ()
 infos ()
 isInstalled ()
 isPaused ()
 isPending ($status)
 isRunning ()
 isStopped ()
 reset ()
 restart ()
 setBinPath ($binPath)
 setDisplayName ($displayName)
 setErrorControl ($errorControl)
 setName ($name)
 setNssm ($nssm)
 setParams ($params)
 setStartType ($startType)
 start ()
 status ($timeout=true)
 stop ()
 waitForServiceDeletion ($maxWaitTime=30)

Static Public Member Functions

static getVbsKeys ()

Data Fields

const PENDING_TIMEOUT = 20
const SERVER_ERROR_IGNORE = '0'
const SERVER_ERROR_NORMAL = '1'
const SERVICE_AUTO_START = '2'
const SERVICE_DEMAND_START = '3'
const SERVICE_DISABLED = '4'
const SLEEP_TIME = 500000
const VBS_DESCRIPTION = 'Description'
const VBS_DISPLAY_NAME = 'DisplayName'
const VBS_NAME = 'Name'
const VBS_PATH_NAME = 'PathName'
const VBS_STATE = 'State'
const WIN32_ERROR_ACCESS_DENIED = '5'
const WIN32_ERROR_CIRCULAR_DEPENDENCY = '423'
const WIN32_ERROR_DATABASE_DOES_NOT_EXIST = '429'
const WIN32_ERROR_DEPENDENT_SERVICES_RUNNING = '41B'
const WIN32_ERROR_DUPLICATE_SERVICE_NAME = '436'
const WIN32_ERROR_FAILED_SERVICE_CONTROLLER_CONNECT = '427'
const WIN32_ERROR_INSUFFICIENT_BUFFER = '7A'
const WIN32_ERROR_INVALID_DATA = 'D'
const WIN32_ERROR_INVALID_HANDLE = '6'
const WIN32_ERROR_INVALID_LEVEL = '7C'
const WIN32_ERROR_INVALID_NAME = '7B'
const WIN32_ERROR_INVALID_PARAMETER = '57'
const WIN32_ERROR_INVALID_SERVICE_ACCOUNT = '421'
const WIN32_ERROR_INVALID_SERVICE_CONTROL = '41C'
const WIN32_ERROR_PATH_NOT_FOUND = '3'
const WIN32_ERROR_SERVICE_ALREADY_RUNNING = '420'
const WIN32_ERROR_SERVICE_CANNOT_ACCEPT_CTRL = '425'
const WIN32_ERROR_SERVICE_DATABASE_LOCKED = '41F'
const WIN32_ERROR_SERVICE_DEPENDENCY_DELETED = '433'
const WIN32_ERROR_SERVICE_DEPENDENCY_FAIL = '42C'
const WIN32_ERROR_SERVICE_DISABLED = '422'
const WIN32_ERROR_SERVICE_DOES_NOT_EXIST = '424'
const WIN32_ERROR_SERVICE_EXISTS = '431'
const WIN32_ERROR_SERVICE_LOGON_FAILED = '42D'
const WIN32_ERROR_SERVICE_MARKED_FOR_DELETE = '430'
const WIN32_ERROR_SERVICE_NO_THREAD = '41E'
const WIN32_ERROR_SERVICE_NOT_ACTIVE = '426'
const WIN32_ERROR_SERVICE_REQUEST_TIMEOUT = '41D'
const WIN32_ERROR_SHUTDOWN_IN_PROGRESS = '45B'
const WIN32_NO_ERROR = '0'
const WIN32_SERVICE_CONTINUE_PENDING = '5'
const WIN32_SERVICE_NA = '0'
const WIN32_SERVICE_PAUSE_PENDING = '6'
const WIN32_SERVICE_PAUSED = '7'
const WIN32_SERVICE_RUNNING = '4'
const WIN32_SERVICE_START_PENDING = '2'
const WIN32_SERVICE_STOP_PENDING = '3'
const WIN32_SERVICE_STOPPED = '1'

Private Member Functions

 callWin32Service ($function, $param, $checkError=false)
 getWin32ErrorCodeDesc ($code)
 getWin32ServiceStatusDesc ($status)
 writeLog ($log)

Private Attributes

 $binPath
 $displayName
 $errorControl
 $latestError
 $latestStatus
 $name
 $nssm
 $params
 $startType

Static Private Attributes

static $loggedFunctions = array()

Detailed Description

Class Win32Service

This class provides an interface to manage Windows services. It includes methods to create, delete, start, stop, and query the status of services. It also handles logging and error reporting for service operations.

Definition at line 17 of file class.win32service.php.

Constructor & Destructor Documentation

◆ __construct()

__construct ( $name)

Constructor for the Win32Service class.

Parameters
string$nameThe name of the service.

Definition at line 96 of file class.win32service.php.

97 {
98 Log::initClass( $this );
99 $this->name = $name;
100 }
static initClass($classInstance)

References $name, and Log\initClass().

Member Function Documentation

◆ callWin32Service()

callWin32Service ( $function,
$param,
$checkError = false )
private

Calls a Win32 service function.

Parameters
string$functionThe function name.
mixed$paramThe parameter to pass to the function.
bool$checkErrorWhether to check for errors.
Returns
mixed The result of the function call.

Definition at line 138 of file class.win32service.php.

138 : mixed
139 {
140 $result = false;
141 if ( function_exists( $function ) ) {
142 if (!isset(self::$loggedFunctions[$function])) {
143 Log::trace('Win32 function: ' . $function . ' exists');
144 self::$loggedFunctions[$function] = true;
145 }
146
147 // Special handling for win32_query_service_status to prevent hanging
148 if ($function === 'win32_query_service_status') {
149 Log::trace("Using enhanced handling for win32_query_service_status");
150
151 // Set a shorter timeout for this specific function
152 $originalTimeout = ini_get('max_execution_time');
153 set_time_limit(5); // 5 seconds timeout
154
155 try {
156 // Ensure proper parameter handling for PHP 8.2.3 compatibility
157 $result = call_user_func($function, $param);
158
159 // Reset the timeout
160 set_time_limit($originalTimeout);
161
162 if ($checkError && $result !== null) {
163 // Convert to int before using dechex for PHP 8.2.3 compatibility
164 $resultInt = is_numeric($result) ? (int)$result : 0;
165 if (dechex($resultInt) != self::WIN32_NO_ERROR) {
166 $this->latestError = dechex($resultInt);
167 }
168 }
169 } catch (\Win32ServiceException $e) {
170 // Reset the timeout
171 set_time_limit($originalTimeout);
172
173 Log::trace("Win32ServiceException caught: " . $e->getMessage());
174
175 // Handle "service does not exist" exception
176 if (strpos($e->getMessage(), 'service does not exist') !== false) {
177 Log::trace("Service does not exist exception handled for: " . $param);
178 // Return the appropriate error code for "service does not exist"
179 $result = hexdec(self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST);
180 } else {
181 // For other exceptions, log and return false
182 Log::trace("Unhandled Win32ServiceException: " . $e->getMessage());
183 $result = false;
184 }
185 } catch (\Exception $e) {
186 // Reset the timeout
187 set_time_limit($originalTimeout);
188
189 // Catch any other exceptions to prevent application freeze
190 Log::trace("Exception caught in callWin32Service: " . $e->getMessage());
191 $result = false;
192 } catch (\Throwable $e) {
193 // Reset the timeout
194 set_time_limit($originalTimeout);
195
196 // Catch any other throwable (PHP 7+) to prevent application freeze
197 Log::trace("Throwable caught in callWin32Service: " . $e->getMessage());
198 $result = false;
199 }
200 } else {
201 // Standard handling for other functions
202 try {
203 // Ensure proper parameter handling for PHP 8.2.3 compatibility
204 $result = call_user_func($function, $param);
205 if ($checkError && $result !== null) {
206 // Convert to int before using dechex for PHP 8.2.3 compatibility
207 $resultInt = is_numeric($result) ? (int)$result : 0;
208 if (dechex($resultInt) != self::WIN32_NO_ERROR) {
209 $this->latestError = dechex($resultInt);
210 }
211 }
212 } catch (\Win32ServiceException $e) {
213 Log::trace("Win32ServiceException caught: " . $e->getMessage());
214
215 // Handle "service does not exist" exception
216 if (strpos($e->getMessage(), 'service does not exist') !== false) {
217 Log::trace("Service does not exist exception handled for: " . $param);
218 // Return the appropriate error code for "service does not exist"
219 $result = hexdec(self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST);
220 } else {
221 // For other exceptions, log and return false
222 Log::trace("Unhandled Win32ServiceException: " . $e->getMessage());
223 $result = false;
224 }
225 } catch (\Exception $e) {
226 // Catch any other exceptions to prevent application freeze
227 Log::trace("Exception caught in callWin32Service: " . $e->getMessage());
228 $result = false;
229 } catch (\Throwable $e) {
230 // Catch any other throwable (PHP 7+) to prevent application freeze
231 Log::trace("Throwable caught in callWin32Service: " . $e->getMessage());
232 $result = false;
233 }
234 }
235 } else {
236 if (!isset(self::$loggedFunctions[$function])) {
237 Log::trace('Win32 function: ' . $function . ' missing');
238 self::$loggedFunctions[$function] = true;
239 }
240 }
241 return $result;
242 }
$result
static trace($data, $file=null)

References $result, and Log\trace().

Referenced by create(), delete(), start(), status(), and stop().

◆ create()

create ( )

Creates the service.

Returns
bool True if the service was created successfully, false otherwise.

Definition at line 352 of file class.win32service.php.

352 : bool
353 {
354 global $bearsamppBins;
355
356 Log::trace("Starting Win32Service::create for service: " . $this->getName());
357
358 if ( $this->getName() == BinPostgresql::SERVICE_NAME ) {
359 Log::trace("PostgreSQL service detected - using specialized installation");
360 $bearsamppBins->getPostgresql()->rebuildConf();
361 Log::trace("PostgreSQL configuration rebuilt");
362
363 $bearsamppBins->getPostgresql()->initData();
364 Log::trace("PostgreSQL data initialized");
365
367 Log::trace("PostgreSQL service installation " . ($result ? "succeeded" : "failed"));
368 return $result;
369 }
370
371 if ( $this->getNssm() instanceof Nssm ) {
372 Log::trace("Using NSSM for service installation");
373
374 $nssmEnvPath = Util::getAppBinsRegKey( false );
375 Log::trace("NSSM environment path (bins): " . $nssmEnvPath);
376
377 $nssmEnvPath .= Nssm::getNssmEnvPaths();
378 Log::trace("NSSM environment path (with additional paths): " . $nssmEnvPath);
379
380 $nssmEnvPath .= '%SystemRoot%/system32;';
381 $nssmEnvPath .= '%SystemRoot%;';
382 $nssmEnvPath .= '%SystemRoot%/system32/Wbem;';
383 $nssmEnvPath .= '%SystemRoot%/system32/WindowsPowerShell/v1.0';
384 Log::trace("NSSM final environment PATH: " . $nssmEnvPath);
385
386 $this->getNssm()->setEnvironmentExtra( 'PATH=' . $nssmEnvPath );
387 Log::trace("NSSM service parameters:");
388 Log::trace("-> Name: " . $this->getNssm()->getName());
389 Log::trace("-> DisplayName: " . $this->getNssm()->getDisplayName());
390 Log::trace("-> BinPath: " . $this->getNssm()->getBinPath());
391 Log::trace("-> Params: " . $this->getNssm()->getParams());
392 Log::trace("-> Start: " . $this->getNssm()->getStart());
393 Log::trace("-> Stdout: " . $this->getNssm()->getStdout());
394 Log::trace("-> Stderr: " . $this->getNssm()->getStderr());
395
396 $result = $this->getNssm()->create();
397 Log::trace("NSSM service creation " . ($result ? "succeeded" : "failed"));
398 if (!$result) {
399 Log::trace("NSSM error: " . $this->getNssm()->getLatestError());
400 }
401 return $result;
402 }
403
404 Log::trace("Using win32_create_service for service installation");
405 $serviceParams = array(
406 'service' => $this->getName(),
407 'display' => $this->getDisplayName(),
408 'description' => $this->getDisplayName(),
409 'path' => $this->getBinPath(),
410 'params' => $this->getParams(),
411 'start_type' => $this->getStartType() != null ? $this->getStartType() : self::SERVICE_DEMAND_START,
412 'error_control' => $this->getErrorControl() != null ? $this->getErrorControl() : self::SERVER_ERROR_NORMAL,
413 );
414
415 Log::trace("win32_create_service parameters:");
416 foreach ($serviceParams as $key => $value) {
417 Log::trace("-> $key: $value");
418 }
419
420 $result = $this->callWin32Service( 'win32_create_service', $serviceParams, true );
421 // Ensure proper type conversion for PHP 8.2.3 compatibility
422 $resultInt = is_numeric($result) ? (int)$result : 0;
423 $create = $result !== null ? dechex( $resultInt ) : '0';
424 Log::trace("win32_create_service result code: " . $create);
425
426 // Retry once if the SCM has the service marked for deletion from a recent delete()
427 if ( $create == self::WIN32_ERROR_SERVICE_MARKED_FOR_DELETE ) {
428 Log::trace("Service marked for delete, waiting 2s before retry: " . $this->getName());
429 usleep( 2000000 );
430 $result = $this->callWin32Service( 'win32_create_service', $serviceParams, true );
431 $resultInt = is_numeric($result) ? (int)$result : 0;
432 $create = $result !== null ? dechex( $resultInt ) : '0';
433 Log::trace("win32_create_service retry result code: " . $create);
434 }
435
436 $this->writeLog( 'Create service: ' . $create . ' (status: ' . $this->status() . ')' );
437 $this->writeLog( '-> service: ' . $this->getName() );
438 $this->writeLog( '-> display: ' . $this->getDisplayName() );
439 $this->writeLog( '-> description: ' . $this->getDisplayName() );
440 $this->writeLog( '-> path: ' . $this->getBinPath() );
441 $this->writeLog( '-> params: ' . $this->getParams() );
442 $this->writeLog( '-> start_type: ' . ($this->getStartType() != null ? $this->getStartType() : self::SERVICE_DEMAND_START) );
443 $this->writeLog( '-> service: ' . ($this->getErrorControl() != null ? $this->getErrorControl() : self::SERVER_ERROR_NORMAL) );
444
445 if ( $create != self::WIN32_NO_ERROR ) {
446 Log::trace("Service creation failed with error code: " . $create);
447 return false;
448 }
449 elseif ( !$this->isInstalled() ) {
450 Log::trace("Service created but not found as installed");
451 $this->latestError = self::WIN32_NO_ERROR;
452 return false;
453 }
454
455 Log::trace("Service created successfully: " . $this->getName());
456 return true;
457 }
global $bearsamppBins
static installPostgresqlService()
static getNssmEnvPaths()
static getAppBinsRegKey($fromRegistry=true)
callWin32Service($function, $param, $checkError=false)
status($timeout=true)

References $bearsamppBins, $result, callWin32Service(), Util\getAppBinsRegKey(), getBinPath(), getDisplayName(), getErrorControl(), getLatestError(), getName(), getNssm(), Nssm\getNssmEnvPaths(), getParams(), getStartType(), Batch\installPostgresqlService(), isInstalled(), BinPostgresql\SERVICE_NAME, status(), Log\trace(), and writeLog().

Referenced by reset().

◆ delete()

delete ( )

Deletes the service.

Returns
bool True if the service was deleted successfully, false otherwise.

Definition at line 464 of file class.win32service.php.

464 : bool
465 {
466 Log::trace("Starting Win32Service::delete for service: " . $this->getName());
467 Log::trace("Checking if service is installed: " . $this->getName());
468
469 if ( !$this->isInstalled() ) {
470 Log::trace("Service is not installed, skipping deletion: " . $this->getName());
471 return true;
472 }
473
474 Log::trace("Stopping service before deletion: " . $this->getName());
475 $this->stop();
476
477 if ( $this->getNssm() instanceof Nssm ) {
478 $childExe = basename( $this->getNssm()->getBinPath() );
479 Log::trace("Killing NSSM child process after stop: " . $childExe);
480 Win32Ps::killBins( [$childExe] );
481 }
482
483 if ( $this->getName() == BinPostgresql::SERVICE_NAME ) {
484 Log::trace("PostgreSQL service detected - using specialized uninstallation");
486 Log::trace("PostgreSQL service uninstallation " . ($result ? "succeeded" : "failed"));
487 return $result;
488 }
489
490 Log::trace("Calling win32_delete_service for service: " . $this->getName());
491 $result = $this->callWin32Service( 'win32_delete_service', $this->getName(), true );
492 // Ensure proper type conversion for PHP 8.2.3 compatibility
493 $resultInt = is_numeric($result) ? (int)$result : 0;
494 $delete = $result !== null ? dechex( $resultInt ) : '0';
495 Log::trace("Delete service result code: " . $delete);
496 $this->writeLog( 'Delete service ' . $this->getName() . ': ' . $delete . ' (status: ' . $this->status() . ')' );
497
498 if ( $delete != self::WIN32_NO_ERROR && $delete != self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST ) {
499 return false;
500 }
501 elseif ( $this->isInstalled() ) {
502 $this->latestError = self::WIN32_NO_ERROR;
503
504 return false;
505 }
506
507 return true;
508 }
static uninstallPostgresqlService()
static killBins($refreshProcs=false)

References $result, callWin32Service(), getBinPath(), getName(), getNssm(), isInstalled(), Win32Ps\killBins(), BinPostgresql\SERVICE_NAME, status(), stop(), Log\trace(), Batch\uninstallPostgresqlService(), and writeLog().

◆ ensureReset()

ensureReset ( )

Ensures the service is properly reset (deleted and verified deleted). This is more robust than just calling delete() as it waits for confirmation.

Returns
bool True if service was successfully reset, false otherwise

Definition at line 1227 of file class.win32service.php.

1227 : bool
1228 {
1229 Log::trace("Starting ensureReset for service: " . $this->getName());
1230
1231 // First, make sure service is stopped
1232 if ($this->isRunning()) {
1233 Log::trace("Service is still running, stopping it first");
1234 if (!$this->stop()) {
1235 Log::trace("Failed to stop service during ensureReset");
1236 return false;
1237 }
1238 usleep(1000000); // 1 second wait after stop
1239 }
1240
1241 // Delete the service
1242 Log::trace("Deleting service");
1243 if (!$this->delete()) {
1244 Log::trace("Service deletion failed, but continuing with wait");
1245 }
1246
1247 // Wait for the service to be completely removed
1248 if (!$this->waitForServiceDeletion(30)) {
1249 Log::trace("Service deletion did not complete within timeout, but continuing");
1250 // Even if we timeout, give it a moment and try to create anyway
1251 usleep(2000000); // 2 seconds
1252 }
1253
1254 Log::trace("ensureReset completed for service: " . $this->getName());
1255 return true;
1256 }
waitForServiceDeletion($maxWaitTime=30)

References getName(), isRunning(), stop(), Log\trace(), and waitForServiceDeletion().

◆ fastServiceCheck()

fastServiceCheck ( )

Fast service check using sc.exe (Windows Service Control utility). This is much faster than WMI/VBS queries and less prone to hanging.

Returns
array|false Service information array or false if service doesn't exist

Definition at line 668 of file class.win32service.php.

669 {
670 Log::trace("Starting fastServiceCheck for service: " . $this->getName());
671
672 $startTime = microtime(true);
673
674 // Use sc.exe to query service - this is very fast and reliable
675 // Execute with hidden window to prevent command prompt flash
676 Log::trace("Executing: sc query " . $this->getName());
677
678 $output = CommandRunner::execCombined('sc', ['query', $this->getName()]);
679 $duration = round(microtime(true) - $startTime, 3);
680
681 Log::trace("sc.exe query completed in " . $duration . "s");
682
683 if ($output === null || $output === false) {
684 Log::trace("sc.exe returned null/false, service likely doesn't exist");
685 return false;
686 }
687
688 // Check if service doesn't exist
689 if (stripos($output, 'does not exist') !== false ||
690 stripos($output, 'FAILED') !== false ||
691 stripos($output, '1060') !== false) { // Error code 1060 = service doesn't exist
692 Log::trace("Service doesn't exist: " . $this->getName());
693 return false;
694 }
695
696 // Service exists - parse basic info
697 $serviceInfo = [];
698
699 // Extract service name
700 if (preg_match('/SERVICE_NAME:\s*(.+)/i', $output, $matches)) {
701 $serviceInfo[self::VBS_NAME] = trim($matches[1]);
702 }
703
704 // Extract display name
705 if (preg_match('/DISPLAY_NAME:\s*(.+)/i', $output, $matches)) {
706 $serviceInfo[self::VBS_DISPLAY_NAME] = trim($matches[1]);
707 }
708
709 // Extract state
710 if (preg_match('/STATE\s*:\s*\d+\s+(\w+)/i', $output, $matches)) {
711 $state = trim($matches[1]);
712 $serviceInfo[self::VBS_STATE] = $state;
713 Log::trace("Service state: " . $state);
714 }
715
716 // If we have basic info, service exists - get full details if needed
717 if (!empty($serviceInfo)) {
718 Log::trace("Service exists, getting full details");
719
720 // Use sc qc to get configuration details (including path)
721 $configOutput = CommandRunner::execCombined('sc', ['qc', $this->getName()]);
722
723 if ($configOutput !== null && $configOutput !== false && preg_match('/BINARY_PATH_NAME\s*:\s*(.+)/i', $configOutput, $matches)) {
724 $serviceInfo[self::VBS_PATH_NAME] = trim($matches[1]);
725 Log::trace("Service path: " . $serviceInfo[self::VBS_PATH_NAME]);
726 }
727
728 // Get description if available
729 if ($configOutput !== null && $configOutput !== false && preg_match('/DISPLAY_NAME\s*:\s*(.+)/i', $configOutput, $matches)) {
730 $serviceInfo[self::VBS_DESCRIPTION] = trim($matches[1]);
731 }
732
733 Log::trace("Fast service check successful for: " . $this->getName());
734 return $serviceInfo;
735 }
736
737 Log::trace("Could not parse service info from sc.exe output");
738 return false;
739 }
static execCombined(string $executable, array $args=[])

References CommandRunner\execCombined(), getName(), and Log\trace().

Referenced by infos().

◆ getBinPath()

getBinPath ( )

Gets the binary path of the service.

Returns
string The binary path of the service.

Definition at line 1037 of file class.win32service.php.

1037 : string
1038 {
1039 return $this->binPath;
1040 }

References $binPath.

Referenced by create(), and delete().

◆ getDisplayName()

getDisplayName ( )

Gets the display name of the service.

Returns
string The display name of the service.

Definition at line 1017 of file class.win32service.php.

1017 : string
1018 {
1019 return $this->displayName;
1020 }

References $displayName.

Referenced by create().

◆ getError()

getError ( )

Gets a detailed error message for the latest error encountered by the service.

Returns
string|null The detailed error message, or null if no error.

Definition at line 1163 of file class.win32service.php.

1164 {
1165 global $bearsamppLang;
1166 if ( $this->latestError != self::WIN32_NO_ERROR ) {
1167 // Ensure proper type conversion for PHP 8.2.3 compatibility
1168 $errorInt = is_numeric($this->latestError) ? hexdec( $this->latestError ) : 0;
1169 return $bearsamppLang->getValue( Lang::ERROR ) . ' ' .
1170 $this->latestError . ' (' . $errorInt . ' : ' . $this->getWin32ErrorCodeDesc( $this->latestError ) . ')';
1171 }
1172 elseif ( $this->latestStatus != self::WIN32_SERVICE_NA ) {
1173 // Ensure proper type conversion for PHP 8.2.3 compatibility
1174 $statusInt = is_numeric($this->latestStatus) ? hexdec( $this->latestStatus ) : 0;
1175 return $bearsamppLang->getValue( Lang::STATUS ) . ' ' .
1176 $this->latestStatus . ' (' . $statusInt . ' : ' . $this->getWin32ServiceStatusDesc( $this->latestStatus ) . ')';
1177 }
1178
1179 return null;
1180 }
global $bearsamppLang
const ERROR
const STATUS
getWin32ServiceStatusDesc($status)

References $bearsamppLang, Lang\ERROR, getWin32ErrorCodeDesc(), getWin32ServiceStatusDesc(), and Lang\STATUS.

◆ getErrorControl()

getErrorControl ( )

Gets the error control setting of the service.

Returns
string The error control setting of the service.

Definition at line 1097 of file class.win32service.php.

1097 : string
1098 {
1099 return $this->errorControl;
1100 }

References $errorControl.

Referenced by create().

◆ getLatestError()

getLatestError ( )

Gets the latest error encountered by the service.

Returns
string The latest error encountered by the service.

Definition at line 1153 of file class.win32service.php.

1154 {
1155 return $this->latestError;
1156 }

References $latestError.

Referenced by create().

◆ getLatestStatus()

getLatestStatus ( )

Gets the latest status of the service.

Returns
string The latest status of the service.

Definition at line 1143 of file class.win32service.php.

1144 {
1145 return $this->latestStatus;
1146 }

References $latestStatus.

◆ getName()

getName ( )

Gets the name of the service.

Returns
string The name of the service.

Definition at line 997 of file class.win32service.php.

997 : string
998 {
999 return $this->name;
1000 }

References $name.

Referenced by create(), delete(), ensureReset(), fastServiceCheck(), infos(), isInstalled(), isPaused(), isRunning(), isStopped(), start(), status(), stop(), and waitForServiceDeletion().

◆ getNssm()

getNssm ( )

Gets the NSSM instance associated with the service.

Returns
Nssm The NSSM instance.

Definition at line 1117 of file class.win32service.php.

1118 {
1119 return $this->nssm;
1120 }

References $nssm.

Referenced by create(), delete(), and infos().

◆ getParams()

getParams ( )

Gets the parameters for the service.

Returns
string The parameters for the service.

Definition at line 1057 of file class.win32service.php.

1057 : string
1058 {
1059 return $this->params;
1060 }

References $params.

Referenced by create().

◆ getStartType()

getStartType ( )

Gets the start type of the service.

Returns
string The start type of the service.

Definition at line 1077 of file class.win32service.php.

1077 : string
1078 {
1079 return $this->startType;
1080 }

References $startType.

Referenced by create().

◆ getVbsKeys()

getVbsKeys ( )
static

Returns an array of VBS keys used for service information.

Returns
array The array of VBS keys.

Definition at line 118 of file class.win32service.php.

118 : array
119 {
120 return array(
121 self::VBS_NAME,
122 self::VBS_DISPLAY_NAME,
123 self::VBS_DESCRIPTION,
124 self::VBS_PATH_NAME,
125 self::VBS_STATE
126 );
127 }

◆ getWin32ErrorCodeDesc()

getWin32ErrorCodeDesc ( $code)
private

Returns a description of the Win32 error code.

Parameters
string$codeThe error code.
Returns
string|null The description of the error code, or null if the code is not recognized.

Definition at line 981 of file class.win32service.php.

981 : ?string
982 {
983 switch ( $code ) {
984 case self::WIN32_ERROR_ACCESS_DENIED:
985 return 'The handle to the SCM database does not have the appropriate access rights.';
986 // ... other cases ...
987 default:
988 return null;
989 }
990 }

Referenced by getError().

◆ getWin32ServiceStatusDesc()

getWin32ServiceStatusDesc ( $status)
private

Returns a description of the Win32 service status.

Parameters
string$statusThe status code.
Returns
string|null The status description.

Definition at line 942 of file class.win32service.php.

942 : ?string
943 {
944 switch ( $status ) {
945 case self::WIN32_SERVICE_CONTINUE_PENDING:
946 return 'The service continue is pending.';
947
948 case self::WIN32_SERVICE_PAUSE_PENDING:
949 return 'The service pause is pending.';
950
951 case self::WIN32_SERVICE_PAUSED:
952 return 'The service is paused.';
953
954 case self::WIN32_SERVICE_RUNNING:
955 return 'The service is running.';
956
957 case self::WIN32_SERVICE_START_PENDING:
958 return 'The service is starting.';
959
960 case self::WIN32_SERVICE_STOP_PENDING:
961 return 'The service is stopping.';
962
963 case self::WIN32_SERVICE_STOPPED:
964 return 'The service is not running.';
965
966 case self::WIN32_SERVICE_NA:
967 return 'Cannot retrieve service status.';
968
969 default:
970 return null;
971 }
972 }

Referenced by getError().

◆ infos()

infos ( )

Retrieves information about the service. Performance optimization: Uses fast sc.exe check first, falls back to VBS if needed.

Returns
array|false The service information, or false on failure.

Definition at line 747 of file class.win32service.php.

748 {
749 Log::trace("Starting Win32Service::infos for service: " . $this->getName());
750
751 try {
752 // Set a timeout for the entire operation
753 $startTime = microtime(true);
754 $timeout = 10; // 10 seconds timeout for the entire operation
755
756 if ($this->getNssm() instanceof Nssm) {
757 Log::trace("Using NSSM to get service info");
758 $result = $this->getNssm()->infos();
759 Log::trace("NSSM info retrieval completed in " . round(microtime(true) - $startTime, 2) . " seconds");
760 return $result;
761 }
762
763 // Performance optimization: Try fast sc.exe check first
764 Log::trace("Attempting fast service check using sc.exe");
765 $fastResult = $this->fastServiceCheck();
766
767 if ($fastResult !== false) {
768 $duration = round(microtime(true) - $startTime, 3);
769 Log::trace("Fast service check succeeded in " . $duration . "s (saved 5-10s)");
770 Log::debug("Performance: Fast service check used for " . $this->getName() . ", saved 5-10 seconds");
771 return $fastResult;
772 }
773
774 // Fast check returned false - service doesn't exist
775 if ($fastResult === false) {
776 $duration = round(microtime(true) - $startTime, 3);
777 Log::trace("Fast service check determined service doesn't exist in " . $duration . "s");
778 return false;
779 }
780
781 // Fallback to VBS (should rarely be needed now)
782 Log::trace("Falling back to VBS for service info");
783
784 // Use set_time_limit to prevent PHP script timeout
785 $originalTimeout = ini_get('max_execution_time');
786 set_time_limit(15); // 15 seconds timeout
787
788 // Create a separate process to get service info with a timeout
790
791 // Reset the timeout
792 set_time_limit($originalTimeout);
793
794 // Check if we've exceeded our timeout
795 if (microtime(true) - $startTime > $timeout) {
796 Log::trace("Timeout exceeded in infos() method, returning false");
797 return false;
798 }
799
800 Log::trace("VBS info retrieval completed in " . round(microtime(true) - $startTime, 2) . " seconds");
801 return $result;
802 } catch (\Exception $e) {
803 Log::trace("Exception in infos() method: " . $e->getMessage() . ", returning false");
804 return false;
805 } catch (\Throwable $e) {
806 Log::trace("Throwable in infos() method: " . $e->getMessage() . ", returning false");
807 return false;
808 }
809 }
static debug($data, $file=null)
static getServiceInfo($serviceName, $properties=[])

References $result, Log\debug(), fastServiceCheck(), getName(), getNssm(), Win32Native\getServiceInfo(), and Log\trace().

◆ isInstalled()

isInstalled ( )

Checks if the service is installed.

Returns
bool True if the service is installed, false otherwise.

Definition at line 816 of file class.win32service.php.

816 : bool
817 {
818 Log::trace("Checking if service is installed: " . $this->getName());
819
820 try {
821 // Set a timeout for the entire operation
822 $startTime = microtime(true);
823 $timeout = 15; // 15 seconds timeout for the entire operation
824
825 // Call status() with a try-catch to ensure we don't get stuck
826 $status = $this->status();
827
828 // Check if we've exceeded our timeout
829 if (microtime(true) - $startTime > $timeout) {
830 Log::trace("Timeout exceeded in isInstalled() method, assuming service is not installed");
831 $this->writeLog('isInstalled ' . $this->getName() . ': NO (timeout exceeded)');
832 return false;
833 }
834
835 $isInstalled = $status != self::WIN32_SERVICE_NA;
836
837 Log::trace("Service " . $this->getName() . " installation status: " . ($isInstalled ? "YES" : "NO") . " (status code: " . $status . ")");
838 $this->writeLog('isInstalled ' . $this->getName() . ': ' . ($isInstalled ? 'YES' : 'NO') . ' (status: ' . $status . ')');
839
840 return $isInstalled;
841 } catch (\Exception $e) {
842 Log::trace("Exception in isInstalled() method: " . $e->getMessage() . ", assuming service is not installed");
843 $this->writeLog('isInstalled ' . $this->getName() . ': NO (exception: ' . $e->getMessage() . ')');
844 return false;
845 } catch (\Throwable $e) {
846 Log::trace("Throwable in isInstalled() method: " . $e->getMessage() . ", assuming service is not installed");
847 $this->writeLog('isInstalled ' . $this->getName() . ': NO (throwable: ' . $e->getMessage() . ')');
848 return false;
849 }
850 }

References getName(), status(), Log\trace(), and writeLog().

Referenced by create(), and delete().

◆ isPaused()

isPaused ( )

Checks if the service is paused.

Returns
bool True if the service is paused, false otherwise.

Definition at line 893 of file class.win32service.php.

893 : bool
894 {
895 Log::trace("Checking if service is paused: " . $this->getName());
896
897 $status = $this->status();
898 $isPaused = $status == self::WIN32_SERVICE_PAUSED;
899
900 Log::trace("Service " . $this->getName() . " paused status: " . ($isPaused ? "YES" : "NO") . " (status code: " . $status . ")");
901 $this->writeLog( 'isPaused ' . $this->getName() . ': ' . ($isPaused ? 'YES' : 'NO') . ' (status: ' . $status . ')' );
902
903 return $isPaused;
904 }

References getName(), status(), Log\trace(), and writeLog().

◆ isPending()

isPending ( $status)

Checks if the service is in a pending state.

Parameters
string$statusThe status to check.
Returns
bool True if the service is in a pending state, false otherwise.

Definition at line 913 of file class.win32service.php.

913 : bool
914 {
915 $isPending = $status == self::WIN32_SERVICE_START_PENDING || $status == self::WIN32_SERVICE_STOP_PENDING
916 || $status == self::WIN32_SERVICE_CONTINUE_PENDING || $status == self::WIN32_SERVICE_PAUSE_PENDING;
917
918 Log::trace("Checking if status is pending: " . $status . " - Result: " . ($isPending ? "YES" : "NO"));
919
920 if ($isPending) {
921 if ($status == self::WIN32_SERVICE_START_PENDING) {
922 Log::trace("Service is in START_PENDING state");
923 } else if ($status == self::WIN32_SERVICE_STOP_PENDING) {
924 Log::trace("Service is in STOP_PENDING state");
925 } else if ($status == self::WIN32_SERVICE_CONTINUE_PENDING) {
926 Log::trace("Service is in CONTINUE_PENDING state");
927 } else if ($status == self::WIN32_SERVICE_PAUSE_PENDING) {
928 Log::trace("Service is in PAUSE_PENDING state");
929 }
930 }
931
932 return $isPending;
933 }

References Log\trace().

Referenced by status().

◆ isRunning()

isRunning ( )

Checks if the service is running.

Returns
bool True if the service is running, false otherwise.

Definition at line 857 of file class.win32service.php.

857 : bool
858 {
859 Log::trace("Checking if service is running: " . $this->getName());
860
861 $status = $this->status();
862 $isRunning = $status == self::WIN32_SERVICE_RUNNING;
863
864 Log::trace("Service " . $this->getName() . " running status: " . ($isRunning ? "YES" : "NO") . " (status code: " . $status . ")");
865 $this->writeLog( 'isRunning ' . $this->getName() . ': ' . ($isRunning ? 'YES' : 'NO') . ' (status: ' . $status . ')' );
866
867 return $isRunning;
868 }

References getName(), status(), Log\trace(), and writeLog().

Referenced by ensureReset(), and start().

◆ isStopped()

isStopped ( )

Checks if the service is stopped.

Returns
bool True if the service is stopped, false otherwise.

Definition at line 875 of file class.win32service.php.

875 : bool
876 {
877 Log::trace("Checking if service is stopped: " . $this->getName());
878
879 $status = $this->status();
880 $isStopped = $status == self::WIN32_SERVICE_STOPPED;
881
882 Log::trace("Service " . $this->getName() . " stopped status: " . ($isStopped ? "YES" : "NO") . " (status code: " . $status . ")");
883 $this->writeLog( 'isStopped ' . $this->getName() . ': ' . ($isStopped ? 'YES' : 'NO') . ' (status: ' . $status . ')' );
884
885 return $isStopped;
886 }

References getName(), status(), Log\trace(), and writeLog().

Referenced by stop().

◆ reset()

reset ( )

Resets the service by deleting and recreating it.

Returns
bool True if the service was reset successfully, false otherwise.

Definition at line 515 of file class.win32service.php.

515 : bool
516 {
517 if ( $this->delete() ) {
518 usleep( self::SLEEP_TIME );
519
520 return $this->create();
521 }
522
523 return false;
524 }

References create().

◆ restart()

restart ( )

Restarts the service by stopping and then starting it.

Returns
bool True if the service was restarted successfully, false otherwise.

Definition at line 653 of file class.win32service.php.

653 : bool
654 {
655 if ( $this->stop() ) {
656 return $this->start();
657 }
658
659 return false;
660 }

References start(), and stop().

◆ setBinPath()

setBinPath ( $binPath)

Sets the binary path of the service.

Parameters
string$binPathThe binary path to set.

Definition at line 1047 of file class.win32service.php.

1047 : void
1048 {
1049 $this->binPath = str_replace( '"', '', UtilPath::formatWindowsPath( $binPath ) );
1050 }
static formatWindowsPath($path)

References $binPath, and UtilPath\formatWindowsPath().

Referenced by setNssm().

◆ setDisplayName()

setDisplayName ( $displayName)

Sets the display name of the service.

Parameters
string$displayNameThe display name to set.

Definition at line 1027 of file class.win32service.php.

1027 : void
1028 {
1029 $this->displayName = $displayName;
1030 }

References $displayName.

Referenced by setNssm().

◆ setErrorControl()

setErrorControl ( $errorControl)

Sets the error control setting of the service.

Parameters
string$errorControlThe error control setting to set.

Definition at line 1107 of file class.win32service.php.

1107 : void
1108 {
1109 $this->errorControl = $errorControl;
1110 }

References $errorControl.

◆ setName()

setName ( $name)

Sets the name of the service.

Parameters
string$nameThe name to set.

Definition at line 1007 of file class.win32service.php.

1007 : void
1008 {
1009 $this->name = $name;
1010 }

References $name.

◆ setNssm()

setNssm ( $nssm)

Sets the NSSM instance associated with the service.

Parameters
Nssm$nssmThe NSSM instance to set.

Definition at line 1127 of file class.win32service.php.

1128 {
1129 if ( $nssm instanceof Nssm ) {
1130 $this->setDisplayName( $nssm->getDisplayName() );
1131 $this->setBinPath( $nssm->getBinPath() );
1132 $this->setParams( $nssm->getParams() );
1133 $this->setStartType( $nssm->getStart() );
1134 $this->nssm = $nssm;
1135 }
1136 }
setStartType($startType)
setDisplayName($displayName)

References $nssm, setBinPath(), setDisplayName(), setParams(), and setStartType().

◆ setParams()

setParams ( $params)

Sets the parameters for the service.

Parameters
string$paramsThe parameters to set.

Definition at line 1067 of file class.win32service.php.

1067 : void
1068 {
1069 $this->params = $params;
1070 }

References $params.

Referenced by setNssm().

◆ setStartType()

setStartType ( $startType)

Sets the start type of the service.

Parameters
string$startTypeThe start type to set.

Definition at line 1087 of file class.win32service.php.

1087 : void
1088 {
1089 $this->startType = $startType;
1090 }

References $startType.

Referenced by setNssm().

◆ start()

start ( )

Starts the service.

Returns
bool True if the service was started successfully, false otherwise.

Definition at line 531 of file class.win32service.php.

531 : bool
532 {
533 global $bearsamppBins;
534
535 Log::info('Attempting to start service: ' . $this->getName());
536
537 if ( $this->getName() == BinMysql::SERVICE_NAME ) {
538 $bearsamppBins->getMysql()->initData();
539 }
540 elseif ( $this->getName() == BinMariadb::SERVICE_NAME ) {
541 $bearsamppBins->getMariadb()->initData();
542 }
543 elseif ( $this->getName() == BinMailpit::SERVICE_NAME ) {
544 $bearsamppBins->getMailpit()->rebuildConf();
545 }
546 elseif ( $this->getName() == BinMemcached::SERVICE_NAME ) {
547 $bearsamppBins->getMemcached()->rebuildConf();
548 }
549 elseif ( $this->getName() == BinPostgresql::SERVICE_NAME ) {
550 $bearsamppBins->getPostgresql()->rebuildConf();
551 $bearsamppBins->getPostgresql()->initData();
552 }
553 elseif ( $this->getName() == BinXlight::SERVICE_NAME ) {
554 $bearsamppBins->getXlight()->rebuildConf();
555 }
556
557
558 $result = $this->callWin32Service( 'win32_start_service', $this->getName(), true );
559 // Ensure proper type conversion for PHP 8.2.3 compatibility
560 $resultInt = is_numeric($result) ? (int)$result : 0;
561 $start = $result !== null ? dechex( $resultInt ) : '0';
562 Log::debug( 'Start service ' . $this->getName() . ': ' . $start . ' (status: ' . $this->status() . ')' );
563
564 if ( $start != self::WIN32_NO_ERROR && $start != self::WIN32_ERROR_SERVICE_ALREADY_RUNNING ) {
565
566 // Write error to log
567 Log::error('Failed to start service: ' . $this->getName() . ' with error code: ' . $start);
568
569 if ( $this->getName() == BinApache::SERVICE_NAME ) {
570 $cmdOutput = $bearsamppBins->getApache()->getCmdLineOutput( BinApache::CMD_SYNTAX_CHECK );
571 if ( !$cmdOutput['syntaxOk'] ) {
572 file_put_contents(
573 $bearsamppBins->getApache()->getErrorLog(),
574 '[' . date( 'Y-m-d H:i:s', time() ) . '] [error] ' . $cmdOutput['content'] . PHP_EOL,
575 FILE_APPEND
576 );
577 }
578 }
579 elseif ( $this->getName() == BinMysql::SERVICE_NAME ) {
580 $cmdOutput = $bearsamppBins->getMysql()->getCmdLineOutput( BinMysql::CMD_SYNTAX_CHECK );
581 if ( !$cmdOutput['syntaxOk'] ) {
582 file_put_contents(
583 $bearsamppBins->getMysql()->getErrorLog(),
584 '[' . date( 'Y-m-d H:i:s', time() ) . '] [error] ' . $cmdOutput['content'] . PHP_EOL,
585 FILE_APPEND
586 );
587 }
588 }
589 elseif ( $this->getName() == BinMariadb::SERVICE_NAME ) {
590 $cmdOutput = $bearsamppBins->getMariadb()->getCmdLineOutput( BinMariadb::CMD_SYNTAX_CHECK );
591 if ( !$cmdOutput['syntaxOk'] ) {
592 file_put_contents(
593 $bearsamppBins->getMariadb()->getErrorLog(),
594 '[' . date( 'Y-m-d H:i:s', time() ) . '] [error] ' . $cmdOutput['content'] . PHP_EOL,
595 FILE_APPEND
596 );
597 }
598 }
599
600 return false;
601 }
602 elseif ( !$this->isRunning() ) {
603 $this->latestError = self::WIN32_NO_ERROR;
604 Log::error('Service ' . $this->getName() . ' is not running after start attempt.');
605 $this->latestError = null;
606 return false;
607 }
608
609 Log::info('Service ' . $this->getName() . ' started successfully.');
610 return true;
611 }
const CMD_SYNTAX_CHECK
const SERVICE_NAME
const CMD_SYNTAX_CHECK
static info($data, $file=null)
static error($data, $file=null)

References $bearsamppBins, $result, callWin32Service(), BinApache\CMD_SYNTAX_CHECK, BinMariadb\CMD_SYNTAX_CHECK, BinMysql\CMD_SYNTAX_CHECK, Log\debug(), Log\error(), getName(), Log\info(), isRunning(), BinApache\SERVICE_NAME, BinMailpit\SERVICE_NAME, BinMariadb\SERVICE_NAME, BinMemcached\SERVICE_NAME, BinMysql\SERVICE_NAME, BinPostgresql\SERVICE_NAME, BinXlight\SERVICE_NAME, and status().

Referenced by restart().

◆ status()

status ( $timeout = true)

Queries the status of the service.

Parameters
bool$timeoutWhether to use a timeout.
Returns
string The status of the service.

Definition at line 251 of file class.win32service.php.

251 : string
252 {
253 usleep( self::SLEEP_TIME );
254
255 $this->latestStatus = self::WIN32_SERVICE_NA;
256 $maxtime = time() + self::PENDING_TIMEOUT;
257
258 Log::trace("Querying status for service: " . $this->getName() . " (timeout: " . ($timeout ? "enabled" : "disabled") . ")");
259 if ($timeout) {
260 Log::trace("Max timeout time set to: " . date('Y-m-d H:i:s', $maxtime));
261 }
262
263 // Add a safety counter to prevent infinite loops
264 $loopCount = 0;
265 $maxLoops = 5; // Maximum number of attempts
266 $startTime = microtime(true);
267
268 try {
269 while ( ($this->latestStatus == self::WIN32_SERVICE_NA || $this->isPending( $this->latestStatus )) && $loopCount < $maxLoops ) {
270 $loopCount++;
271 Log::trace("Calling win32_query_service_status for service: " . $this->getName() . " (attempt " . $loopCount . " of " . $maxLoops . ")");
272
273 // Add a timeout check before making the call
274 if (microtime(true) - $startTime > 10) { // 10 seconds overall timeout
275 Log::trace("Overall timeout reached before making service status call");
276 break;
277 }
278
279 $this->latestStatus = $this->callWin32Service( 'win32_query_service_status', $this->getName() );
280
281 if ( is_array( $this->latestStatus ) && isset( $this->latestStatus['CurrentState'] ) ) {
282 // Ensure proper type conversion for PHP 8.2.3 compatibility
283 $stateInt = is_numeric($this->latestStatus['CurrentState']) ? (int)$this->latestStatus['CurrentState'] : 0;
284 $this->latestStatus = dechex( $stateInt );
285 Log::trace("Service status returned as array, CurrentState: " . $this->latestStatus);
286 }
287 elseif ( $this->latestStatus !== null ) {
288 // Ensure proper type conversion for PHP 8.2.3 compatibility
289 $statusInt = is_numeric($this->latestStatus) ? (int)$this->latestStatus : 0;
290 $statusHex = dechex( $statusInt );
291 Log::trace("Service status returned as value: " . $statusHex);
292
293 if ( $statusHex == self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST ) {
294 $this->latestStatus = $statusHex;
295 Log::trace("Service does not exist, breaking loop");
296 break; // Exit the loop immediately if service doesn't exist
297 }
298 } else {
299 Log::trace("Service status query returned null");
300 // If we get a null result, assume service does not exist to avoid hanging
301 if ($loopCount >= 2) // Only do this after at least one retry
302 {
303 Log::trace("Multiple null results, assuming service does not exist");
304 $this->latestStatus = self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST;
305 break;
306 }
307 }
308
309 if ( $timeout && $maxtime < time() ) {
310 Log::trace("Timeout reached while querying service status");
311 break;
312 }
313
314 // Only sleep if we're going to loop again
315 if ($loopCount < $maxLoops && ($this->latestStatus == self::WIN32_SERVICE_NA || $this->isPending($this->latestStatus))) {
316 Log::trace("Sleeping before next status check attempt");
317 usleep(self::SLEEP_TIME);
318 }
319 }
320 } catch (\Exception $e) {
321 Log::trace("Exception in status method: " . $e->getMessage());
322 // If an exception occurs, assume service does not exist
323 $this->latestStatus = self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST;
324 } catch (\Throwable $e) {
325 Log::trace("Throwable in status method: " . $e->getMessage());
326 // If a throwable occurs, assume service does not exist
327 $this->latestStatus = self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST;
328 }
329
330 if ($loopCount >= $maxLoops) {
331 Log::trace("Maximum query attempts reached for service: " . $this->getName());
332 }
333
334 $elapsedTime = microtime(true) - $startTime;
335 Log::trace("Status check completed in " . round($elapsedTime, 2) . " seconds after " . $loopCount . " attempts");
336
337 if ( $this->latestStatus == self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST ) {
338 $this->latestError = $this->latestStatus;
339 $this->latestStatus = self::WIN32_SERVICE_NA;
340 Log::trace("Service does not exist, setting status to NA");
341 }
342
343 Log::trace("Final status for service " . $this->getName() . ": " . $this->latestStatus);
344 return $this->latestStatus;
345 }

References $latestStatus, callWin32Service(), getName(), isPending(), and Log\trace().

Referenced by create(), delete(), isInstalled(), isPaused(), isRunning(), isStopped(), start(), stop(), and waitForServiceDeletion().

◆ stop()

stop ( )

Stops the service.

Returns
bool True if the service was stopped successfully, false otherwise.

Definition at line 618 of file class.win32service.php.

618 : bool
619 {
620 Log::trace("Starting Win32Service::stop for service: " . $this->getName());
621
622 Log::trace("Calling win32_stop_service for service: " . $this->getName());
623 $result = $this->callWin32Service( 'win32_stop_service', $this->getName(), true );
624
625 // Ensure proper type conversion for PHP 8.2.3 compatibility
626 $resultInt = is_numeric($result) ? (int)$result : 0;
627 $stop = $result !== null ? dechex( $resultInt ) : '0';
628 Log::trace("Stop service result code: " . $stop);
629
630 Log::trace("Checking current status after stop attempt");
631 $currentStatus = $this->status();
632 Log::trace("Current status: " . $currentStatus);
633
634 $this->writeLog( 'Stop service ' . $this->getName() . ': ' . $stop . ' (status: ' . $currentStatus . ')' );
635
636 if ( $stop != self::WIN32_NO_ERROR ) {
637 return false;
638 }
639 elseif ( !$this->isStopped() ) {
640 $this->latestError = self::WIN32_NO_ERROR;
641
642 return false;
643 }
644
645 return true;
646 }

References $result, callWin32Service(), getName(), isStopped(), status(), Log\trace(), and writeLog().

Referenced by delete(), ensureReset(), and restart().

◆ waitForServiceDeletion()

waitForServiceDeletion ( $maxWaitTime = 30)

Waits for the service to be completely removed from the SCM database. This is important after deletion because the SCM marks services for deletion but they remain visible briefly, preventing re-creation.

Parameters
int$maxWaitTimeMaximum time to wait in seconds (default 30)
Returns
bool True if service is confirmed deleted, false on timeout

Definition at line 1191 of file class.win32service.php.

1191 : bool
1192 {
1193 $startTime = time();
1194 $maxTime = $startTime + $maxWaitTime;
1195 $checkCount = 0;
1196
1197 Log::trace("Waiting for service deletion: " . $this->getName() . " (max wait: " . $maxWaitTime . "s)");
1198
1199 while (time() < $maxTime) {
1200 $checkCount++;
1201 $status = $this->status(false);
1202 Log::trace("Service deletion check #" . $checkCount . " - Status: " . $status . " at " . date('Y-m-d H:i:s'));
1203
1204 // Service doesn't exist or is definitely not there
1205 if ($status == self::WIN32_SERVICE_NA ||
1206 $status == self::WIN32_ERROR_SERVICE_DOES_NOT_EXIST) {
1207 $elapsedTime = time() - $startTime;
1208 Log::trace("Service deletion confirmed after " . $elapsedTime . " seconds");
1209 return true;
1210 }
1211
1212 // Wait a bit before checking again
1213 usleep(500000); // 0.5 seconds
1214 }
1215
1216 $totalWaitTime = time() - $startTime;
1217 Log::trace("Service deletion timeout after " . $totalWaitTime . " seconds - service still exists: " . $this->getName());
1218 return false;
1219 }

References getName(), status(), and Log\trace().

Referenced by ensureReset().

◆ writeLog()

writeLog ( $log)
private

Writes a log entry.

Parameters
string$logThe log message.

Definition at line 107 of file class.win32service.php.

107 : void
108 {
109 global $bearsamppRoot;
110 Log::debug( $log, $bearsamppRoot->getServicesLogFilePath() );
111 }
global $bearsamppRoot

References $bearsamppRoot, and Log\debug().

Referenced by create(), delete(), isInstalled(), isPaused(), isRunning(), isStopped(), and stop().

Field Documentation

◆ $binPath

$binPath
private

Definition at line 79 of file class.win32service.php.

Referenced by getBinPath(), and setBinPath().

◆ $displayName

$displayName
private

Definition at line 78 of file class.win32service.php.

Referenced by getDisplayName(), and setDisplayName().

◆ $errorControl

$errorControl
private

Definition at line 82 of file class.win32service.php.

Referenced by getErrorControl(), and setErrorControl().

◆ $latestError

$latestError
private

Definition at line 86 of file class.win32service.php.

Referenced by getLatestError().

◆ $latestStatus

$latestStatus
private

Definition at line 85 of file class.win32service.php.

Referenced by getLatestStatus(), and status().

◆ $loggedFunctions

$loggedFunctions = array()
staticprivate

Definition at line 89 of file class.win32service.php.

◆ $name

$name
private

Definition at line 77 of file class.win32service.php.

Referenced by __construct(), getName(), and setName().

◆ $nssm

$nssm
private

Definition at line 83 of file class.win32service.php.

Referenced by getNssm(), and setNssm().

◆ $params

$params
private

Definition at line 80 of file class.win32service.php.

Referenced by getParams(), and setParams().

◆ $startType

$startType
private

Definition at line 81 of file class.win32service.php.

Referenced by getStartType(), and setStartType().

◆ PENDING_TIMEOUT

const PENDING_TIMEOUT = 20

Definition at line 68 of file class.win32service.php.

◆ SERVER_ERROR_IGNORE

const SERVER_ERROR_IGNORE = '0'

Definition at line 61 of file class.win32service.php.

◆ SERVER_ERROR_NORMAL

const SERVER_ERROR_NORMAL = '1'

Definition at line 62 of file class.win32service.php.

Referenced by BinMariadb\reload(), BinMysql\reload(), and BinPostgresql\reload().

◆ SERVICE_AUTO_START

const SERVICE_AUTO_START = '2'

Definition at line 64 of file class.win32service.php.

◆ SERVICE_DEMAND_START

const SERVICE_DEMAND_START = '3'

Definition at line 65 of file class.win32service.php.

Referenced by BinMariadb\reload(), BinMysql\reload(), and BinPostgresql\reload().

◆ SERVICE_DISABLED

const SERVICE_DISABLED = '4'

Definition at line 66 of file class.win32service.php.

◆ SLEEP_TIME

const SLEEP_TIME = 500000

Definition at line 69 of file class.win32service.php.

◆ VBS_DESCRIPTION

const VBS_DESCRIPTION = 'Description'

Definition at line 73 of file class.win32service.php.

◆ VBS_DISPLAY_NAME

const VBS_DISPLAY_NAME = 'DisplayName'

Definition at line 72 of file class.win32service.php.

◆ VBS_NAME

const VBS_NAME = 'Name'

Definition at line 71 of file class.win32service.php.

◆ VBS_PATH_NAME

const VBS_PATH_NAME = 'PathName'

Definition at line 74 of file class.win32service.php.

Referenced by Nssm\infos(), and ActionStartup\prepareService().

◆ VBS_STATE

const VBS_STATE = 'State'

Definition at line 75 of file class.win32service.php.

◆ WIN32_ERROR_ACCESS_DENIED

const WIN32_ERROR_ACCESS_DENIED = '5'

Definition at line 30 of file class.win32service.php.

◆ WIN32_ERROR_CIRCULAR_DEPENDENCY

const WIN32_ERROR_CIRCULAR_DEPENDENCY = '423'

Definition at line 31 of file class.win32service.php.

◆ WIN32_ERROR_DATABASE_DOES_NOT_EXIST

const WIN32_ERROR_DATABASE_DOES_NOT_EXIST = '429'

Definition at line 32 of file class.win32service.php.

◆ WIN32_ERROR_DEPENDENT_SERVICES_RUNNING

const WIN32_ERROR_DEPENDENT_SERVICES_RUNNING = '41B'

Definition at line 33 of file class.win32service.php.

◆ WIN32_ERROR_DUPLICATE_SERVICE_NAME

const WIN32_ERROR_DUPLICATE_SERVICE_NAME = '436'

Definition at line 34 of file class.win32service.php.

◆ WIN32_ERROR_FAILED_SERVICE_CONTROLLER_CONNECT

const WIN32_ERROR_FAILED_SERVICE_CONTROLLER_CONNECT = '427'

Definition at line 35 of file class.win32service.php.

◆ WIN32_ERROR_INSUFFICIENT_BUFFER

const WIN32_ERROR_INSUFFICIENT_BUFFER = '7A'

Definition at line 36 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_DATA

const WIN32_ERROR_INVALID_DATA = 'D'

Definition at line 37 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_HANDLE

const WIN32_ERROR_INVALID_HANDLE = '6'

Definition at line 38 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_LEVEL

const WIN32_ERROR_INVALID_LEVEL = '7C'

Definition at line 39 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_NAME

const WIN32_ERROR_INVALID_NAME = '7B'

Definition at line 40 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_PARAMETER

const WIN32_ERROR_INVALID_PARAMETER = '57'

Definition at line 41 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_SERVICE_ACCOUNT

const WIN32_ERROR_INVALID_SERVICE_ACCOUNT = '421'

Definition at line 42 of file class.win32service.php.

◆ WIN32_ERROR_INVALID_SERVICE_CONTROL

const WIN32_ERROR_INVALID_SERVICE_CONTROL = '41C'

Definition at line 43 of file class.win32service.php.

◆ WIN32_ERROR_PATH_NOT_FOUND

const WIN32_ERROR_PATH_NOT_FOUND = '3'

Definition at line 44 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_ALREADY_RUNNING

const WIN32_ERROR_SERVICE_ALREADY_RUNNING = '420'

Definition at line 45 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_CANNOT_ACCEPT_CTRL

const WIN32_ERROR_SERVICE_CANNOT_ACCEPT_CTRL = '425'

Definition at line 46 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_DATABASE_LOCKED

const WIN32_ERROR_SERVICE_DATABASE_LOCKED = '41F'

Definition at line 47 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_DEPENDENCY_DELETED

const WIN32_ERROR_SERVICE_DEPENDENCY_DELETED = '433'

Definition at line 48 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_DEPENDENCY_FAIL

const WIN32_ERROR_SERVICE_DEPENDENCY_FAIL = '42C'

Definition at line 49 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_DISABLED

const WIN32_ERROR_SERVICE_DISABLED = '422'

Definition at line 50 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_DOES_NOT_EXIST

const WIN32_ERROR_SERVICE_DOES_NOT_EXIST = '424'

Definition at line 51 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_EXISTS

const WIN32_ERROR_SERVICE_EXISTS = '431'

Definition at line 52 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_LOGON_FAILED

const WIN32_ERROR_SERVICE_LOGON_FAILED = '42D'

Definition at line 53 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_MARKED_FOR_DELETE

const WIN32_ERROR_SERVICE_MARKED_FOR_DELETE = '430'

Definition at line 54 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_NO_THREAD

const WIN32_ERROR_SERVICE_NO_THREAD = '41E'

Definition at line 55 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_NOT_ACTIVE

const WIN32_ERROR_SERVICE_NOT_ACTIVE = '426'

Definition at line 56 of file class.win32service.php.

◆ WIN32_ERROR_SERVICE_REQUEST_TIMEOUT

const WIN32_ERROR_SERVICE_REQUEST_TIMEOUT = '41D'

Definition at line 57 of file class.win32service.php.

◆ WIN32_ERROR_SHUTDOWN_IN_PROGRESS

const WIN32_ERROR_SHUTDOWN_IN_PROGRESS = '45B'

Definition at line 58 of file class.win32service.php.

◆ WIN32_NO_ERROR

const WIN32_NO_ERROR = '0'

Definition at line 59 of file class.win32service.php.

◆ WIN32_SERVICE_CONTINUE_PENDING

const WIN32_SERVICE_CONTINUE_PENDING = '5'

Definition at line 20 of file class.win32service.php.

◆ WIN32_SERVICE_NA

const WIN32_SERVICE_NA = '0'

Definition at line 27 of file class.win32service.php.

◆ WIN32_SERVICE_PAUSE_PENDING

const WIN32_SERVICE_PAUSE_PENDING = '6'

Definition at line 21 of file class.win32service.php.

◆ WIN32_SERVICE_PAUSED

const WIN32_SERVICE_PAUSED = '7'

Definition at line 22 of file class.win32service.php.

◆ WIN32_SERVICE_RUNNING

const WIN32_SERVICE_RUNNING = '4'

Definition at line 23 of file class.win32service.php.

◆ WIN32_SERVICE_START_PENDING

const WIN32_SERVICE_START_PENDING = '2'

Definition at line 24 of file class.win32service.php.

◆ WIN32_SERVICE_STOP_PENDING

const WIN32_SERVICE_STOP_PENDING = '3'

Definition at line 25 of file class.win32service.php.

◆ WIN32_SERVICE_STOPPED

const WIN32_SERVICE_STOPPED = '1'

Definition at line 26 of file class.win32service.php.


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