pclose()
Функция PHP pclose() закрывает указатель на процесс, открытый функцией popen(), и возвращает код завершения процесса.
Функция PHP pclose()
Функция PHP pclose() закрывает указатель на процесс — специальный поток, возвращаемый функцией popen() при запуске внешней команды. В отличие от fclose(), которая просто закрывает обычный файловый дескриптор, pclose() делает кое-что дополнительное: ожидает завершения дочернего процесса и возвращает его код завершения.
На этой странице рассматриваются синтаксис, возвращаемое значение (с одним важным нюансом), полный пример чтения и закрытия, а также когда стоит использовать proc_open() вместо pclose().
Зачем нужна pclose()
popen() запускает команду оболочки и предоставляет вам канал для передачи ввода ('w'-режим) или чтения вывода ('r'-режим). Этот канал поддерживается реальным процессом ОС. Если просто оставить дескриптор открытым — или закрыть его неправильной функцией — процесс может остаться зомби, а его код завершения будет потерян. pclose() является правильным аналогом: она сбрасывает буфер канала, блокирует выполнение до завершения дочернего процесса, освобождает его ресурсы и возвращает код завершения, чтобы скрипт мог реагировать на успех или ошибку.
Всегда используйте
popen()иpclose()в паре. Использованиеfclose()для дескриптора, полученного отpopen(), является неопределённым поведением.
Синтаксис
pclose(resource $handle): intПараметры
Функция принимает один параметр:
$handle— указатель на процесс, возвращённый функциейpopen(). Передача ресурса другого типа является недопустимой.
Возвращаемое значение
pclose() возвращает статус завершения процесса в виде целого числа (это исходное значение из C-функции pclose — на большинстве систем фактический код завершения хранится в старшем байте). Функция возвращает -1, если процесс не удалось завершить корректно. В старых версиях PHP передача некорректного дескриптора вызывает предупреждение и возвращает FALSE.
Чтобы получить обычный код завершения в Unix-подобных системах, сдвиньте значение вправо на 8 бит:
$status = pclose($handle);
$exitCode = $status >> 8; // 0 means the command succeededПример
Откройте команду, прочитайте её вывод, затем закройте канал и проверьте результат:
<?php
// Run an external command and read its output.
$handle = popen('ls -la', 'r');
if ($handle === false) {
die("Failed to start the command.\n");
}
$output = '';
while (!feof($handle)) {
$output .= fread($handle, 1024);
}
echo $output;
// Close the pipe and capture the process exit status.
$status = pclose($handle);
$exitCode = $status >> 8;
echo "Command exited with code: $exitCode\n";Мы открываем указатель на процесс с помощью popen(), читаем весь вывод в цикле с помощью fread() (один вызов fread может не захватить всё при большом объёме вывода), затем закрываем канал с помощью pclose() и декодируем код завершения. Код завершения 0 по соглашению означает успех.
Распространённые ошибки
- Не путайте
fclose()иpclose(). Дескриптор отpopen()должен закрываться черезpclose(), а дескриптор отfopen()— черезfclose(). pclose()блокирует выполнение. Функция ожидает завершения дочернего процесса. Если команда никогда не завершится, скрипт зависнет.- Читайте перед закрытием.
pclose()может отбросить не прочитанный буферизованный вывод, поэтому сначала завершите чтение канала. - Один канал — одно направление. Канал
popen()является либо читаемым, либо записываемым, но не обоими сразу — для двунаправленного взаимодействия используйтеproc_open().
Когда использовать proc_open()
popen()/pclose() отлично подходят для быстрой одноразовой команды, когда нужен только её вывод или ввод данных в неё. Когда необходимы оба направления одновременно, раздельные stdout и stderr, управление окружением или рабочим каталогом — используйте proc_open(), которая предоставляет полный двунаправленный контроль над запущенным процессом.
Заключение
pclose() является обязательным компаньоном функции popen(): она закрывает канал процесса, ожидает завершения команды и возвращает её код завершения, чтобы можно было проверить успешность выполнения. Всегда используйте эти функции в паре, читайте канал перед закрытием и не забывайте сдвигать статус вправо на 8 бит для получения реального кода завершения в Unix-системах. Для всего, что выходит за рамки однонаправленного канала, используйте proc_open().