proc_open

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

proc_open Executa um comando e abre ponteiros de arquivo para entrada/saída

Descrição

proc_open(
    array|string $command,
    array $descriptor_spec,
    array &$pipes,
    ?string $cwd = null,
    ?array $env_vars = null,
    ?array $options = null
): resource|false

proc_open() é similar a popen() mas fornece um grau de controle muito maior sobre a execução do programa.

Parâmetros

command

A linha de comando a executar, como uma string. Caracteres especiais precisam ser escapados adequadamente, e o uso de aspas deve ser apropriadamente aplicado.

Note: No Windows, a menos que bypass_shell esteja definido para true no parâmetro options, o comando em command é passado para cmd.exe (na verdade, %ComSpec%) com a opção /c como uma string sem aspas (isto é, exatamente como fornecido a proc_open()). Isto pode fazer com que cmd.exe remova as aspas que envolvem o comando em command (para detalhes, consulte a documentação do cmd.exe), resultando em comportamento inesperado e potencialmente perigoso, porque as mensagens de erro de cmd.exe podem conter (partes dos) comandos passados em command (veja exemplo abaixo).

A partir do PHP 7.4.0, command pode ser passado como um array de parâmetros de comandos. Neste caso, o processo será aberto diretamente (sem passar por um "shell") e o PHP irá gerenciar qualquer escape de argumentos se necessário.

Note:

No Windows, o escape de argumentos dos elementos do array assume que a análise de linha de comando é compatível com a análise dos argumentos de linha de comando feita pelas bibliotecas em tempo de execução do VC.

descriptor_spec

Um array indexado onte a chave representa o número descritor e o valor representa como o PHP irá passar esse descritor ao processo filho. 0 é stdin, 1 é stdout e 2 é stderr.

Cada elemento pode ser:

  • Um array descrevendo o tubo a ser passado ao processo. O primeiro elemento é o tipo do descritor e o segundo elemento é uma opção para o tipo fornecido. Tipos válidos são pipe (o segundo elemento pode ser r para passar a ponta de leitura do tubo ao processo, ou w para passar a ponta de escrita) e file (o segundo elemento é um nome de arquivo). Observe que qualquer outro tipo diferente de w é tratado como r.
  • Um recurso de fluxo representando um descritor de arquivo real (ex.: arquivo aberto, um soquete ou STDIN).

O número do descritor de arquivo não é limitado a 0, 1 e 2 - pode-se especificar qualquer número válido de descritor de arquivo e ele será passado ao processo filho. Isto permite que o script consiga operar com outros scripts que são executados como "co-processos". Em particular, isto é útil para passar senhas a programas como PGP, GPG e openssl de uma forma mais segura. Também é útil para ler informações de estado de decritores de arquivos auxiliares fornecidas por estes programas.

pipes

Será definido para um array indexado de ponteiros de arquivos que corresponde à ponta do PHP de qualquer tubo que seja criado.

cwd

O diretório de trabalho inicial para o comando. Precisa ser um caminho de diretório absoluto, ou null se for desejado usar o valor padrão (o diretório de trabalho do processo PHP atual)

env_vars

Um array com as variáveis de ambiente para o comando que será executado, ou null para usar o mesmo ambiente do processo PHP atual

options

Permite especificar opções adicionais. As opções atualmente suportadas incluem:

  • suppress_errors (somente Windows): suprime erros gerados por esta função quando definida para true
  • bypass_shell (somente Windows): ignora o "shell" cmd.exe quando definida para true
  • blocking_pipes (somente Windows): força tubos no modo de bloqueio quando definida para true
  • create_process_group (somente Windows): permite ao processo filho lidar com eventos CTRL quando definida para true
  • create_new_console (somente Windows): o novo processo terá um novo console, ao invés de herdar o console do processo pai

Valor Retornado

Retorna um recurso representando o processo, que deve ser liberado usando proc_close() quando seu uso tiver sido finalizado. Em caso de falha retorna false.

Registro de Alterações

Versão Descrição
7.4.4 Adicionada a opção create_new_console ao parâmetro options.
7.4.0 proc_open() agora aceita um array para o parâmetro command.
7.4.0 Adicionada a opção create_process_group ao parâmetro options.

Exemplos

Example #1 Um exemplo de proc_open()

<?php
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin é um tubo de onde o processo filho irá ler
   1 => array("pipe", "w"),  // stdout é um tubo no qual o processo filho irá escrever
   2 => array("file", "/tmp/error-output.txt", "a") // stderr é um arquivo que será escrito
);

$cwd = '/tmp';
$env = array('some_option' => 'aeiou');

$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
    // $pipes agora será parecido com:
    // 0 => manipulador que pode ser escrito, conectado ao stdin filho
    // 1 => manipulador que pode ser lido, conectado ao stdout filho
    // Qualquer saída de erro será anexaa ao /tmp/error-output.txt

    fwrite($pipes[0], '<?php print_r($_ENV); ?>');
    fclose($pipes[0]);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // É importante fechar todos os tubos antes de chamar
    // proc_close para evitar o beco sem saída
    $return_value = proc_close($process);

    echo "comando retornou $return_value\n";
}
?>

O exemplo acima produzirá algo semelhante a:

Array
(
    [some_option] => aeiou
    [PWD] => /tmp
    [SHLVL] => 1
    [_] => /usr/local/bin/php
)
comando retornou 0

Example #2 Peculiaridade de proc_open() no Windows

Embora seja esperado que o programa a seguir pesquise o arquivo filename.txt pelo texto search e mostre os resultados, ele se comporta de maneira bastante diferente.

<?php
$descriptorspec = [STDIN, STDOUT, STDOUT];
$cmd = '"findstr" "search" "filename.txt"';
$proc = proc_open($cmd, $descriptorspec, $pipes);
proc_close($proc);
?>

O exemplo acima produzirá:

'findstr" "search" "filename.txt' is not recognized as an internal or external command,
operable program or batch file.

Para contornar este comportamento, normalmente é suficiente envolver command com aspas adicionais:

$cmd = '""findstr" "search" "filename.txt""';

Notas

Note:

Compatibilidade com Windows: Descritores além de 2 (stderr) estão disponíveis para o processo filho como manipuladores que podem ser herdados, mas como a arquitetura Windows não associa números de descritores de arquivos a manipuladores de baixo nível, o processo filho não tem (ainda) meios de acessar esses manipuladores. Stdin, stdout e stderr funcionam conforme esperado.

Note:

Se for necessário somente um tubo de processo unidirecional (mão única), utilize a função popen(), pois é muito mais fácil de usar.

Veja Também

  • popen() - Abre um processo como ponteiro de arquivo
  • exec() - Executa um programa externo
  • system() - Executa um programa externo e mostra a saída
  • passthru() - Executa um programa externo e mostra a saída bruta
  • stream_select() - Executa o equivalente à chamada de sistema select() nos arrays de fluxos informados com um limite de tempo especificado por segundos e microssegundos
  • O operador crase