Execute PHP script as a Windows service


Under Windows, scripts can be, that's endless run with PHP using a service implemented.

This has the advantage of, that is the memory consumption with the time to infinity, with endless script versions and a recovery and restart functionality can be implemented, to keep the service over long periods of time running.

Furthermore, the service receives from the operating system events, if e.g.. a shutdown is, to be able to stop in time itself and not corrupt data to produce cancellation in a non-atomic operation.

To create a Windows service, you need the win32service PHP library.

You can here them Download and in the php.ini embed:

extension=php_win32service.dll

Create service

To create and control a service, You can use the following code in the file Win32_Service.php Save:

<?php
//No timeouts, Flush Content immediatly
set_time_limit(0);
ob_implicit_flush();

$serviceName = 'FooCommand';

$serviceAction = $argv[1];

switch ($argv[1]) {
    case  'install': {
        $result = win32_create_service(array(
            'service' => $serviceName,
            'display' => $serviceName,
            'description' => $serviceName,
            'params' => sprintf('%s\win32_run.php', __DIR__),
            'recovery_delay'        => 1000,                                               // Recovery action is executed after 10s
            'recovery_action_1'     => WIN32_SC_ACTION_RESTART,
            'recovery_action_2'     => WIN32_SC_ACTION_RESTART,
            'recovery_action_3'     => WIN32_SC_ACTION_RESTART,
            'recovery_reset_period' => 3600,                                                // Reset the fail counter after 1 hour
        ));
        break;
    }
    case  'uninstall': {
        $result = win32_delete_service($serviceName);
        break;
    }
    case  'stop': {
        $result = win32_stop_service($serviceName);
        break;
    }
    case  'status': {
        $ServiceStatus = win32_query_service_status($serviceName);
        if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_STOPPED ) {
            echo "Service Stopped\n\n";
        } else if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_START_PENDING ) {
            echo "Service Start Pending\n\n";
        } else if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_STOP_PENDING ) {
            echo "Service Stop Pending\n\n";
        } else if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_RUNNING ) {
            echo "Service Running\n\n";
        } else if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_CONTINUE_PENDING ) {
            echo "Service Continue Pending\n\n";
        } else if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_PAUSE_PENDING ) {
            echo "Service Pause Pending\n\n";
        } else if ( $ServiceStatus['CurrentState'] == WIN32_SERVICE_PAUSED ) {
            echo "Service Paused\n\n";
        } else{
            echo "Service Unknown\n\n";
        }
        exit;
    }
    default: {
        throw new Exception('unknow argument');
    }
}

switch($result) {
    case WIN32_ERROR_SERVICE_DOES_NOT_EXIST:
        throw new Exception('service not found');
    case WIN32_SERVICE_ERROR_IGNORE:
        die('service successfully installed/uninstalled');
    case WIN32_ERROR_ACCESS_DENIED:
        throw new Exception('access denied, run command as administrator');
    case WIN32_ERROR_SERVICE_EXISTS:
        throw new Exception('service already exists, uninstall service prior');
    case WIN32_ERROR_SERVICE_MARKED_FOR_DELETE:
        throw new Exception(sprintf('service has been marked for deletion, look here https://stackoverflow.com/questions/20561990/how-to-solve-the-specified-service-has-been-marked-for-deletion-error'));
    case WIN32_SERVICE_START_PENDING:
        throw new Exception('service start is pending');
    case WIN32_ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
        echo 'can not connect to service controller'. PHP_EOL;
        break;
    default:
        # search for hex value of result win32service lib
        debug_zval_dump($result);
}

and run (Run CMD as administrator) with:

run with: php win32_service.php install
//or
run with: php win32_service.php uninstall
//or
run with: php win32_service.php status
//or
run with: php win32_service.php stop

Then should see Control Panel-> Services the service FooCommand have been created, which automatically starts when the next Windows startup.

Create Windows service with PHP script

The long-running PHP script

The script, that should be performed on the service is located in the file: win32_run.php

<?php
set_time_limit(0);
ob_implicit_flush();
$serviceName = 'FooCommand';

$result = win32_start_service_ctrl_dispatcher($serviceName);
if (!$result) {
    die("I'm probably not running under the service control manager");
}
debug_zval_dump($result);
win32_set_service_status(WIN32_SERVICE_START_PENDING);

// Some lengthy process to get this service up and running.

win32_set_service_status(WIN32_SERVICE_RUNNING);

while (WIN32_SERVICE_CONTROL_STOP != win32_get_last_control_message()) {
    exec(sprintf('php %s/script.php', __DIR__));
}

In the script.php can the endless code be added now:

<?php
echo "hello service";

The service configuration

The service can be configured precisely in the case of an error:

Service configuration in the event of a fault

Debugging the service

When running the service not right off the bat, can be an error in Control Panel-> Event Viewer give more information:

Windows service event display

Comments are closed.