【问题标题】:PHP escape user input for filenamePHP 转义用户输入的文件名
【发布时间】:2010-11-27 03:01:31
【问题描述】:

我有一个用户可以上传文件的表单,我想为文件命名为[id]_[lastname]_[firstname].pdf。名称是用户输入的,我怕他们输入带有斜线的东西。否则,如果名字是 john/hahaimajerk,则类似 $path = $dir.$filename 的内容可能会导致 $path = 'uploads/2_smith_john/hahaimajerk.pdf'

我真的不想强迫用户将他们的名字限制在任何东西上;只要我能说出原始名称,我不介意在文件名中稍微更改它们的名称。我需要逃脱哪些角色,或者有其他方法可以做到这一点?还是……我只使用mysql_real_escape_string

【问题讨论】:

  • 正如 Alex N. 所说,escapeshellarg 是您正在寻找的内容,但我强烈考虑分配已知安全的文件名并通过您的数据库将它们映射到用户友好的文件名。跨度>
  • 更糟糕的是:想象“/../../../etc/passwd”的名字
  • 一般来说“.”和“..”也很重要。

标签: php


【解决方案1】:

我通常为此使用正则表达式。而不是删除某些特定字符(如斜线、点等),我更喜欢只允许某些字符(如字母数字)

例如,这会将任何不是字母、数字、破折号或下划线的字符替换为下划线:

$escaped = preg_replace('/[^A-Za-z0-9_\-]/', '_', $raw);

破折号前的反斜杠用于转义正则表达式中的破折号,因为破折号用于指定字符范围(例如 A-Z)。

【讨论】:

  • 末尾(或开头)的破折号不被视为范围指示器
  • 使用这种方式,文件名和文件扩展名之间的点也会被转义。
  • @SAMPro 是的,但它是我们正在谈论的文件名,您应该始终在检查 MIME-TYPE 后以某种可靠的方式制作自己的扩展名(例如Fileinfo module
  • /[^\w-]/ 就够了!
【解决方案2】:

mysql_real_escape_string 不会转义斜线。即使escapeshellarg 也不会这样做。你必须使用str_replace:

$path = str_replace('/', '_', $path);

【讨论】:

  • 我担心还有其他可能危险的符号 - 希望 / 是唯一的问题。
  • escapeshellarg 等仅在发送 shell 命令时有用(使用 shell_exec、exec 等),以确保其他运算符(如 ;&& 或反引号)被转义,在为了防止 shell 命令注入(类似于 SQL 注入,但在 shell 中,而且危害更大)。 PHP 的文件系统函数(fopenfile_put_contents 等)不必转义文件名。在您的情况下最坏的情况(即:没有 str_replace),PHP 将无法写入文件并出现“没有这样的文件或目录”错误。
  • 操作系统也可能不允许文件名中的某些字符(例如,Windows 不允许冒号 : 以及各种其他字符),这是此答案无法解决的问题。如果您不确定您的代码将在什么服务器环境上运行,Tommy Lacroix 的回答会好得多。
【解决方案3】:

文件名中唯一的“不安全”字符是 / - 因此您可以使用 str_replace("/","",$filename) 轻松避免问题

【讨论】:

  • "。"而“..”也会造成麻烦。
  • ... 没有/ 是无害的。
  • ...但仍然是保留名称,应该考虑 IMO。
  • . 可能是有害的,如果它是您的整个文件名。比如rmdir(realpath($pathToWeb . '../uploads/' . $userInput))或者类似的情况
  • 因此,您应该使用$filename = preg_replace('((^\.)|\/|(\.$))', '_', $filename) -- 转义 any 斜线和开头或结尾的每个点。
猜你喜欢
  • 2017-01-05
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多