Запуск PHP-скриптов: веб, консоль и eval
Выполнение PHP-кода - одна из базовых задач при разработке на этом языке. В зависимости от окружения и целей используются разные способы: от традиционного запуска через веб-сервер до динамической подстановки кода строкой. В этой статье рассматриваются основные методы, их особенности и типичные трудности.
Основные способы выполнения PHP-кода
Как выполнить PHP-скрипт в production-окружении?
Наиболее эффективное решение - запуск через веб-сервер с PHP-FPM (FastCGI Process Manager). Веб-сервер (Nginx или Apache) передаёт запросы на выполнение PHP-файлов процессу PHP-FPM, который обрабатывает их и возвращает результат клиенту. Этот подход обеспечивает высокую производительность, изоляцию процессов и поддержку множества одновременных соединений.
Пример настройки Nginx + PHP-FPM:
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
После настройки файл index.php в корне сайта будет исполняться при обращении к домену. Для проверки создайте файл с кодом <?php phpinfo(); ?> - в браузере отобразится информация о PHP.
Проблема:
Браузер возвращает содержимое файла как текст, а не исполняет его. Это указывает на то, что PHP не обрабатывается сервером. Решение: убедитесь, что PHP-FPM запущен и сокет (или порт) указан верно, а также что конфигурация Nginx корректно подхвачена (перезапустите nginx).
Как выполнить PHP-код без установленного веб-сервера?
Для разработки и тестирования удобен встроенный сервер PHP, запускаемый из командной строки. Он не предназначен для production, но идеален для локальной работы.
Пример запуска:
php -S localhost:8000
Сервер обслуживает текущую директорию. Указав файл-роутер, можно обрабатывать все запросы через один скрипт:
php -S localhost:8000 index.php
Пошаговое пояснение:
-S- запуск встроенного сервера.localhost:8000- адрес и порт.index.php- файл, который будет выполняться для всех запросов (роутер).
Возможная ошибка:
Сервер не запускается, если порт занят. Решение: укажите другой порт, например php -S localhost:8080.
Как запустить PHP-скрипт на сервере через терминал?
Исполняемые файлы PHP можно запускать напрямую из командной строки (CLI). Это используется для фоновых заданий, cron-скриптов и обработки данных.
Базовая команда:
php /path/to/script.php
Пример скрипта count.php:
<?php
$lines = file('data.txt');
echo 'Количество строк: ' . count($lines);
?>
Результат выполнения:
Количество строк: 42
Для передачи аргументов скрипту используйте массив $argv:
php count.php data.txt
Внутри файла $argv[1] будет содержать data.txt.
Проблема:
Команда php не найдена. Решение: добавьте путь к интерпретатору в переменную окружения PATH или используйте полный путь, например /usr/bin/php.
Как выполнить строку PHP-кода внутри другого скрипта?
Для динамического выполнения кода существует функция eval(). Она принимает строку с PHP-кодом и исполняет её в текущей области видимости. Применяется с осторожностью из-за риска внедрения вредоносного кода.
Пример:
<?php
$code = 'return 2 + 2;';
$result = eval($code);
echo $result;
?>
Результат:
4
Важно: код, передаваемый в eval, должен быть синтаксически корректным. Используйте try..catch с Error для отлова ошибок:
<?php
try {
eval('echo $undefined;');
} catch (Error $e) {
echo 'Ошибка: ' . $e->getMessage();
}
?>
Ошибка синтаксиса:
Если строка содержит ошибку, eval возвращает false и генерирует фатальную ошибку. Используйте error_reporting(0) с последующей проверкой, но лучший подход - валидировать код перед выполнением или заменить eval на безопасные альтернативы (например, анонимные функции).
Как выполнить код из другого файла?
Конструкции include, require, include_once и require_once подключают и выполняют код из указанного файла. Это основной способ повторного использования кода.
Пример:
<?php
require 'config.php'; // выполняет код из config.php
include 'functions.php'; // если файл не найден, выдаёт warning, но скрипт продолжается
?>
Отличие include от require: при ошибке include генерирует предупреждение, require - фатальную ошибку. _once версии предотвращают повторное включение.
Ошибка:
Файл не найден, и скрипт завершается (если require). Решение: проверяйте пути с помощью __DIR__ и используйте абсолютные пути для критичных файлов.
Расширенные примеры выполнения PHP-кода
1. Встроенный сервер с роутером
Можно создать единую точку входа (роутер), которая обрабатывает все запросы. Это удобно для разработки приложений без необходимости настройки виртуальных хостов.
Файл router.php:
<?php
if (preg_match('/\.(?:png|jpg|jpeg|gif|css|js)$/', $_SERVER['REQUEST_URI'])) {
return false; // отдать статичный файл как есть
}
$path = __DIR__ . '/app' . $_SERVER['REQUEST_URI'] . '.php';
if (file_exists($path)) {
require $path;
} else {
http_response_code(404);
echo 'Страница не найдена';
}
?>
Запуск:
php -S localhost:8000 router.php
Результат: при запросе /users будет выполнен файл app/users.php, если он существует.
2. CLI-скрипт с аргументами и опциями
Сценарий командной строки может принимать множество параметров с помощью getopt().
<?php
$options = getopt('f:', ['file:', 'help']);
if (isset($options['help'])) {
echo 'Использование: php convert.php --file input.txt' . PHP_EOL;
exit(0);
}
$filename = $options['file'] ?? $options['f'] ?? null;
if (!$filename) {
fwrite(STDERR, 'Не указан файл' . PHP_EOL);
exit(1);
}
$content = file_get_contents($filename);
echo 'Прочитано ' . strlen($content) . ' байт' . PHP_EOL;
?>
Пример выполнения:
php convert.php --file=document.txt
Прочитано 1024 байт
При неверном параметре выводится сообщение в STDERR и скрипт завершается с кодом 1.
3. eval() с ограничением ресурсов
Для безопасного выполнения динамического кода можно устанавливать лимиты времени и памяти.
<?php
$code = 'for(;;);'; // бесконечный цикл
set_time_limit(2); // ограничение 2 секунды
$maxMemory = 32 * 1024 * 1024; // 32 MB
memory_limit($maxMemory);
try {
$result = eval($code);
var_dump($result);
} catch (Throwable $e) {
echo 'Ошибка: ' . $e->getMessage();
}
?>
Результат: через 2 секунды скрипт будет прерван из-за таймаута, и будет выброшено исключение (если настроено). Обратите внимание: memory_limit() можно изменить только если ini_set не запрещён.
4. include с обработкой ошибок
При использовании include можно подавлять предупреждения и обрабатывать их позже с помощью пользовательского обработчика ошибок.
<?php
set_error_handler(function ($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
});
try {
include 'nonexistent.php';
} catch (ErrorException $e) {
echo 'Не удалось подключить файл: ' . $e->getMessage();
}
restore_error_handler();
?>
Результат:
Не удалось подключить файл: include(nonexistent.php): Failed to open stream: No such file or directory
Этот подход позволяет централизованно обрабатывать ошибки подключения.
5. Запуск PHP-скрипта как отдельного процесса с pcntl_exec
В Linux-среде можно заменить текущий процесс на другой PHP-скрипт через pcntl_exec(). Это полезно для выполнения «тяжёлых» задач в изолированном процессе.
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('Не удалось создать процесс');
} elseif ($pid) {
// родительский процесс
pcntl_wait($status);
echo 'Дочерний процесс завершён с кодом ' . pcntl_wexitstatus($status);
} else {
// дочерний процесс
pcntl_exec('/usr/bin/php', ['/var/scripts/worker.php', '--option=value']);
}
?>
Примечание: функция pcntl_* доступна только при PHP с опцией --enable-pcntl и не работает на Windows. Используйте с осторожностью.
6. Выполнение кода через php://input
PHP поддерживает поток php://input для чтения сырых данных запроса. Можно выполнить код, переданный в POST-запросе (только для образовательных целей; в реальных проектах это небезопасно).
<?php
$code = file_get_contents('php://input');
if (!empty($code)) {
eval($code);
} else {
echo 'Нет кода для выполнения';
}
?>
Пример отправки через curl:
curl -X POST -d 'echo "Hello from POST";' http://localhost:8000/
Hello from POST
Этот метод крайне опасен из-за возможности удалённого выполнения кода (RCE). Применяйте только в изолированной тестовой среде.