Создание инструментов управления сервером на языке PHP

Раздел: Администрирование -> Серверное окружение

Основные подходы к созданию серверных PHP скриптов

Серверный скрипт на PHP может выполнять задачи администрирования: резервное копирование, очистку логов, мониторинг ресурсов. Рассмотрим различные варианты реализации, начиная с простых и заканчивая более надёжными решениями.

Как организовать безопасное выполнение системных команд из PHP?

Наиболее эффективный способ - использовать встроенные функции exec() или shell_exec() с проверкой входных данных. Пример безопасного запуска команды df -h для получения информации о дисках:

$diskUsage = shell_exec('df -h 2>&1');
echo '<pre>' . htmlspecialchars($diskUsage) . '</pre>';

скрипт сервера php (серверный php скрипт)

Такой подход позволяет захватить вывод команды и экранировать его для веб-отображения.

Ошибка: команда не выполняется из-за недостаточных прав. Решение: проверить пользователя веб-сервера (обычно www-data) и добавить ему права sudo на конкретные команды через файл /etc/sudoers.

Как запустить PHP-скрипт по расписанию (cron)?

Для регулярного выполнения скрипта используется cron. Пропишите задачу в crontab:

* * * * * /usr/bin/php /path/to/script.php >> /var/log/script.log 2>&1

Цель: автоматический сбор метрик или очистка кэша. Проблема: скрипт может выполняться дольше интервала cron, что ведёт к наложению запусков. Решение: использовать блокировку файлом (flock).

$lock = fopen('/tmp/script.lock', 'c');
if (!flock($lock, LOCK_EX | LOCK_NB)) { exit('Already running'); }
// код скрипта
flock($lock, LOCK_UN);
fclose($lock);

Типичная ошибка: в cron не указан полный путь к PHP. Используйте which php для определения пути.

Как обрабатывать аргументы командной строки в PHP?

Для написания универсального CLI-скрипта применяйте getopt(). Пример:

$options = getopt('a:b:', ['action:', 'target:']);
if ($options['action'] === 'backup') {
    $target = $options['target'] ?? '/var/www';
    echo 'Backup of ' . $target;
}

Цель: скрипт с разными режимами (backup, restore, clean). Проблема: некорректный ввод аргументов. Реализуйте проверку:

if (!isset($options['action'])) { echo 'Usage: php script.php --action=backup'; exit(1); }

Ошибка: короткие опции путаются с длинными. Рекомендуется использовать только длинные опции для ясности.

Как обеспечить выполнение скрипта только из командной строки, а не из веба?

Добавьте проверку на SAPI:

if (php_sapi_name() !== 'cli') { die('This script is CLI only.'); }

Цель: предотвратить случайный запуск через веб-сервер, что может привести к уязвимостям.

Как логировать действия серверного скрипта?

Используйте error_log() с указанием файла:

error_log('Backup started at ' . date('Y-m-d H:i:s'), 3, '/var/log/myapp.log');

Цель: отслеживание ошибок и успешных запусков. Проблема: переполнение журнала. Добавьте ротацию логов через logrotate или удаление старых записей внутри скрипта.

if (filesize($logfile) > 10485760) { unlink($logfile); }

Расширенные примеры с пояснениями

Пример 1: Многопоточная обработка файлов через pcntl

Для ускорения обработки большого количества файлов (например, архивация) используйте дочерние процессы. Важно: модуль pcntl доступен только в CLI.

Пример
$files = glob('/tmp/data/*.txt');
$maxProcesses = 4;
$children = [];

foreach ($files as $file) {
    $pid = pcntl_fork();
    if ($pid == -1) { die('Fork failed'); }
    if ($pid) {
        $children[] = $pid;
        if (count($children) >= $maxProcesses) {
            pcntl_wait($status);
            array_shift($children);
        }
    } else {
        // код обработки файла
        file_put_contents($file . '.processed', strtoupper(file_get_contents($file)));
        exit(0);
    }
}

foreach ($children as $child) { pcntl_wait($status); }
echo 'Done';
Результат: создаются файлы .processed параллельно до 4 одновременно.

Проблема: при большом количестве файлов можно превысить лимит процессов. Используйте pcntl_wait() с опцией WNOHANG для неблокирующего ожидания.

Пример 2: Работа с сокетами для мониторинга портов

Скрипт проверяет доступность TCP-порта и отправляет уведомление при недоступности.

Пример
$host = '127.0.0.1';
$port = 3306;
$fp = @fsockopen($host, $port, $errno, $errstr, 5);
if (!$fp) {
    $message = "Port $port on $host is down: $errstr";
    error_log($message, 3, '/var/log/portmonitor.log');
    mail('admin@example.com', 'Port Down', $message);
} else {
    fclose($fp);
    echo 'OK';
}
Результат: при недоступности MySQL-порта отправляется email.

Ошибка: скрипт может зависнуть при блокировке сокета. Установите таймаут (5 секунд) и используйте @ для подавления предупреждений.

Пример 3: Резервное копирование базы данных с прогресс-баром

Скрипт делает дамп MySQL и выводит прогресс в терминале (CLI).

Пример
$db = 'mydb';
$backupFile = '/backup/' . $db . '_' . date('Ymd') . '.sql';
$cmd = "mysqldump --single-transaction $db 2>/dev/null";
$output = [];
$returnVar = 0;
exec($cmd, $output, $returnVar);
if ($returnVar === 0) {
    $data = implode("\n", $output);
    $totalLines = count($output);
    $progress = 0;
    $handle = fopen($backupFile, 'w');
    foreach ($output as $line) {
        fwrite($handle, $line . "\n");
        $progress++;
        echo "\rProgress: " . round(($progress/$totalLines)*100) . "%";
    }
    fclose($handle);
} else {
    echo 'Backup failed';
}
Результат: файл дампа и отображение процента выполнения в той же строке.

Проблема: при большом дампе скрипт потребляет много памяти. Используйте passthru() с записью потока напрямую в файл.

Пример 4: Интерактивный скрипт с вводом пароля

Для сценариев, где нужен пароль (например, расшифровка), используйте readline() с отключением эха.

Пример
echo 'Enter password: ';
system('stty -echo');
$password = trim(fgets(STDIN));
system('stty echo');
echo "\n";
// использование пароля
if ($password === 'secret') { echo 'Access granted'; }
Результат: пароль не отображается при вводе.

Ошибка: stty не доступен в Windows. Альтернатива: использовать readline_callback_handler_install().

Серверный PHP скрипт - comments

En
скрипт сервера php (php)