PHP Classes

File: scripts/admin_daemon.php

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   scripts/admin_daemon.php   Download  
File: scripts/admin_daemon.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 3,492 bytes
 

Contents

Class file image Download
#!/usr/bin/env php
<?php

chdir
(__DIR__ . "/../");

require_once
__DIR__ . '/../vendor/autoload.php';

use
BinktermPHP\Admin\AdminDaemonServer;
use
BinktermPHP\Binkp\Logger;
use
BinktermPHP\Config;

function
showUsage()
{
    echo
"Usage: php admin_daemon.php [options]\n";
    echo
"Options:\n";
    echo
" --socket=TARGET Socket target (unix:///path.sock or tcp://127.0.0.1:PORT)\n";
    echo
" --secret=SECRET Shared secret for auth (overrides ADMIN_DAEMON_SECRET)\n";
    echo
" --log-file=FILE Log file path (default: " . Config::getLogPath('admin_daemon.log') . ")\n";
    echo
" --log-level=LEVEL Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL\n";
    echo
" --no-console Disable console logging\n";
    echo
" --pid-file=FILE Write PID file\n";
    echo
" --socket-perms=MODE Set unix socket permissions (octal)\n";
    echo
" --daemon Run as daemon (requires pcntl_fork)\n";
    echo
" --help Show this help message\n";
    echo
"\n";
}

function
parseArgs($argv)
{
   
$args = [];
   
    foreach (
$argv as $arg) {
        if (
strpos($arg, '--') === 0) {
            if (
strpos($arg, '=') !== false) {
                list(
$key, $value) = explode('=', substr($arg, 2), 2);
               
$args[$key] = $value;
            } else {
               
$args[substr($arg, 2)] = true;
            }
        }
    }
   
    return
$args;
}

function
daemonize()
{
   
$pid = pcntl_fork();
   
    if (
$pid == -1) {
        die(
"Could not fork process\n");
    } elseif (
$pid) {
        echo
"Admin daemon started with PID: $pid\n";
        exit(
0);
    }
   
    if (
posix_setsid() == -1) {
        die(
"Could not detach from terminal\n");
    }
   
   
chdir('/');
   
umask(0);

   
fclose(STDIN);
   
fclose(STDOUT);
   
fclose(STDERR);

   
// Reopen fd 0/1/2 to /dev/null so they are not reused by subsequent
    // socket_create() calls. Without this, the first new socket gets fd 0,
    // the second gets fd 1, etc., and any code that writes to PHP's output
    // (e.g. BinkpClient::log() echo fallback) corrupts the socket that
    // happens to occupy fd 1 ? the admin client connection.
   
fopen('/dev/null', 'r'); // fd 0 ? STDIN
   
fopen('/dev/null', 'a'); // fd 1 ? STDOUT
   
fopen('/dev/null', 'a'); // fd 2 ? STDERR
}

function
setConsoleTitle(string $title): void
{
    echo
"\033]0;{$title}\007";
}

$args = parseArgs($argv);

if (isset(
$args['help'])) {
   
showUsage();
    exit(
0);
}

try {
   
$defaultPidFile = __DIR__ . '/../data/run/admin_daemon.pid';
   
$pidFile = $args['pid-file'] ?? (Config::env('ADMIN_DAEMON_PID_FILE') ?: $defaultPidFile);

   
$logLevel = $args['log-level'] ?? 'INFO';
   
$logFile = $args['log-file'] ?? Config::getLogPath('admin_daemon.log');
   
$logToConsole = !isset($args['no-console']);

   
$logger = new Logger($logFile, $logLevel, $logToConsole);

    if (isset(
$args['daemon']) && function_exists('pcntl_fork')) {
       
$logger->setLogToConsole(false);
       
daemonize();
    } else {
       
setConsoleTitle('BinktermPHP Admin Daemon');
    }

   
$pidDir = dirname($pidFile);
    if (!
is_dir($pidDir)) {
        @
mkdir($pidDir, 0755, true);
    }

   
$server = new AdminDaemonServer(
       
$args['socket'] ?? null,
       
$args['secret'] ?? null,
       
$logger,
       
$pidFile,
       
$args['socket-perms'] ?? null
   
);

   
$server->run();
} catch (
Exception $e) {
    echo
"Error: " . $e->getMessage() . "\n";
    exit(
1);
}