Как выйти из команды php exec() с кавычками
Я использую инструмент командной строки Exiv2 в Linux для редактирования метаданных изображения следующим образом:
exiv2 -M"set Iptc.Application2.Caption String This is my caption....." modify IMG.jpg
Я хочу выполнить это из PHP, используя подпись, предоставленную пользователем. Это будет работать, если пользователь не вводит никаких специальных символов:
exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String '.$caption.'" modify IMG.jpg');
Мне нужно разрешить пользователю специальные символы, такие как одинарные и двойные кавычки. Я хотел бы использовать escapeshellcmd() для предотвращения вредоносных данных. Как я могу правильно избежать команды и аргумента, чтобы он работал? Я перепробовал много вариантов, но не могу понять это правильно.
3 ответа
Да, это сложная проблема, потому что команда использует нестандартные аргументы оболочки (например, собственный мета-язык). ImageMagick имеет те же проблемы.
Если вы просто используете escapeshellarg() внутри строки в двойных кавычках, она становится бесполезной. escapeshellcmd() экранирует все специальные символы и безопасен для использования в строке в двойных кавычках. Поэтому вам нужно жестко закодировать одинарные кавычки, чтобы он работал правильно.
exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String \'' . escapeshellcmd($caption) . '\'" modify IMG.jpg');
Причина, по которой escapeshellarg() не будет работать в одной строке в кавычках:
# for this input:
The smith's "; rm -rf *; echo "went to town
# after escapeshellarg()
'The smith\'s "; rm -rf *; echo "went to town'
# Works fine if left as a top-level argument
/usr/bin/command 'The smith\'s "; rm -rf *; echo "went to town'
# BUT if put in a double-quoted string:
/usr/bin/command "subcommand1 'The smith\'s "; rm -rf *; echo "went to town'"
# it is broken into 3 shell commands:
/usr/bin/command "something and 'The smith\'s ";
rm -rf *;
echo "went to town'"
# bad day...
Из-за нестандартных аргументов оболочки Exiv2 нелегко найти простое и надежное решение для правильной обработки предоставленных пользователем кавычек. Существует другое решение, которое, вероятно, будет гораздо более надежным и простым в обслуживании с небольшим снижением производительности.
Запишите инструкции Exiv2 в файл cmds.txt
затем позвоните:
exiv2 -m cmds.txt IMG.jpg
прочитать инструкцию из файла.
Обновление: я реализовал этот метод, и он не требует экранирования предоставленных пользователем данных. Эти данные записываются непосредственно в текстовый файл, который читается в Exiv2. Формат командного файла Exiv2 очень прост и завершается символом новой строки, не допускает экранирования в значениях, поэтому все, что мне нужно сделать, - это предотвратить прохождение новых строк, чего я все равно не разрешал.
Как насчет использования heredoc?
$str = <<<'EOD'
/usr/local/bin/exiv2 -M "set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($str);
Чтобы изменить это, чтобы использовать excapeshellcmd():
$options = excapeshellcmd($caption);
$command = <<<'EOD'
/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($command);