Как передать содержимое переменной через внешнюю команду в php? - PullRequest
3 голосов
/ 07 сентября 2011

У меня есть переменная, которая содержит длинную строку.(в частности, он содержит несколько килобайт javascript-кода)

Я хочу передать эту строку через внешнюю команду, в данном случае javascript-компрессор, и захватить выходные данные внешней команды (сжатый javascript)в php присвоение его переменной.

Я знаю, что в php есть классы для сжатия javascript, но это всего лишь один пример общей проблемы.

изначально мы использовали:

$newvar = passthru("echo $oldvar | compressor");

Это работает для небольших строк, но небезопасно.(если oldvar содержит символы, имеющие особое значение для оболочки, то может произойти все что угодно)

Экранирование с помощью escapeshellarg исправляет это, но решение ломается для более длинных строк из-за ограничений ОС на максимально допустимую длину аргумента.

Я пытался использовать popen("command" "w") и писать в команду - это работает, но вывод команды молча исчезает в пустоте.

Концептуально, я просто хочу сделать эквивалент:

$newvar = external_command($oldvar);

Ответы [ 2 ]

2 голосов
/ 07 сентября 2011

Используя функцию proc_open , вы можете получить дескрипторы как stdout, так и stdin процесса и, таким образом, записать в него свои данные и прочитать результат.

0 голосов
/ 09 сентября 2011

Используя предложение rumpels, я смог придумать следующее решение, которое, кажется, работает хорошо. Размещать его здесь в интересах всех, кто интересуется этим вопросом.

public static function extFilter($command, $content){
    $fds = array(
        0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
        1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
        2 => array("pipe", "w")   // stderr is a pipe that the child will write to
    );
    $process = proc_open($command, $fds, $pipes, NULL, NULL);
    if (is_resource($process)) {
        fwrite($pipes[0], $content);
        fclose($pipes[0]);
        $stdout =  stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);
        $return_value = proc_close($process);
        // Do whatever you want to do with $stderr and the commands exit-code.
    } else {
        // Do whatever you want to do if the command fails to start
    }
    return $stdout;
}

Могут возникать проблемы взаимоблокировки: если отправляемые вами данные превышают объединенные размеры каналов, тогда внешняя команда будет блокироваться, ожидая, что кто-то прочтет ее стандартный вывод, в то время как php заблокирован, ожидая, пока стандартный вывод быть прочитанным, чтобы освободить место для дополнительной информации.

Возможно, PHP как-то решит эту проблему, но стоит проверить, если вы планируете отправлять (или получать) больше данных, чем умещается в каналах.

...