如何使用引号转义 php exec() 命令

发布于 2024-07-30 14:39:21 字数 447 浏览 4 评论 0原文

我使用 Linux 上的 Exiv2 命令行工具来编辑图像元数据,如下所示:

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() 来防止恶意数据。 如何正确转义命令和参数以使其正常工作? 我尝试了很多选择,但我无法做出正确的选择。

I use the Exiv2 command line tool on Linux to edit image metadata like so:

exiv2 -M"set Iptc.Application2.Caption String This is my caption....." modify IMG.jpg

I want to execute this from PHP, using a caption provide by a user. This will work if the user enters no special characters:

exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String '.$caption.'" modify IMG.jpg');

I need to allow the user special characters such as single and double quotes. I would like to use escapeshellcmd() to prevent malicious data. How can I correctly escape the command and the argument so that it works? I have tried many options but I can't get it right.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜妞爱困 2024-08-06 14:39:21

是的,这是一个难题,因为该命令使用非标准 shell 参数(就像它自己的小元语言)。 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...

Yes, this is a hard problem, because the command is using non-standard shell arguments (like it's own little meta-language). ImageMagick has the same issues.

If you simply use escapeshellarg() within a double-quoted string, it is rendered useless. escapeshellcmd() does escape all special characters, and is safe for use in a double-quoted string. So you need to hard code single quotes around it to make it work right.

exec('/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String \'' . escapeshellcmd($caption) . '\'" modify IMG.jpg');

The reason escapeshellarg() will not work in a single quoted string is:

# 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...
↙温凉少女 2024-08-06 14:39:21

使用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);

What about using heredoc?

$str = <<<'EOD'
/usr/local/bin/exiv2 -M "set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($str);

To modify this to use excapeshellcmd():

$options = excapeshellcmd($caption);
$command = <<<'EOD'
/usr/local/bin/exiv2 -M"set Iptc.Application2.Caption String $options" modify IMG.jpg
EOD;
exec($command);
盗梦空间 2024-08-06 14:39:21

由于 Exiv2 的非标准 shell 参数,要找到一个简单而强大的解决方案来正确处理用户提供的引号并不容易。 还有另一种解决方案可能更加可靠且易于维护,但性能损失较小。

将Exiv2指令写入文件cmds.txt,然后调用:

exiv2 -m cmds.txt IMG.jpg

从文件中读取指令。

更新:我已经实现了这个方法,它不需要转义用户提供的数据。 该数据直接写入由 Exiv2 读入的文本文件。 Exiv2 命令文件格式非常简单并且以换行符结尾,不允许在值内转义,因此我需要做的就是防止换行符通过,无论如何我都不允许这样做。

Because of Exiv2's non-standard shell arguments, it is not easy to reach a simple and robust solution to handle user-supplied quotes correctly. There is another solution that is likely to be far more reliable and easy to maintain with a small performance penalty.

Write the Exiv2 instructions to a file cmds.txt, then call:

exiv2 -m cmds.txt IMG.jpg

to read the instructions from the file.

Update: I have implemented this method and it requires no escaping of the user-supplied data. This data is written directly to a text file which is read in by Exiv2. The Exiv2 command file format is very simple and newline-terminated, allow no escaping within values, so all I need to do is prevent newlines from passing through, which I was not allowing anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文