2016-02-28 96 views
0

我正在寻找一个PHP函数来将字符串清理成安全和有效的文件名,而不使用目录分隔符(斜杠)。PHP:推荐的方法来避免路径中的斜线(例如,以防止目录遍历攻击)

理想情况下,它应该是可逆的,它不应该争取更多的名称。

当然我想防止故意的目录遍历攻击。但我也想防止创建子文件夹。

我认为urlencode()会工作,但我想知道这是否足够,和/或如果有更好的或更受欢迎的东西。

此外,如果在Windows上有一些功能同样好(反斜杠作为目录分隔符) - 所以解决方案将是可移植的。

使用案例/情景:

作为数据导入的一部分,我想下载从远程URL文件到本地文件系统。这些网址来自csv文件。它们大多数都可以,但它们可能包含比预期更多的斜线。

E.g.他们大多是这样的:
https://files.example.com/pdf/12345.pdf

但随后单个文件可能是这样的:
https://files.example.com/pdf/1/2345.pdf

这些文件都应该去到同一个目录,例如 https://files.example.com/pdf/12345.pdf - >/destination/dir/12345.pdf

1/2345.pdf这样的文件不应该导致子目录。相反,/应该以某种(可逆的)方式逃脱。例如。与urlencode()这将是1%2F2345.pdf

+1

您是否有其他要求?可读性?双向转换? (即从文件名返回原始URL?)Url编码也被其他许多人使用。 – Kaii

+0

“理想情况下,它应该是可逆的,它不应该争取更多的名字” - 原始问题的一部分:) – donquixote

+0

一个好的答案是一个不仅适用于我而且对其他访问者有用的答案。它可能首先关注可逆情况(其中urlencode()可能是选择的解决方案),然后为需求略有不同的人提供一种或多种替代方案。 – donquixote

回答

2

您可以创建一组替代品。例如,你可以让出现在文件名中的/ char用“(斜线)”之类的东西表示。只需使用str_replace就可以在查找文件名和编码文件名之间进行切换。这只是一个例子。

2

这应该对你有帮助。

输入https://files.example.com/pdf/1/2345.pdf

输出:pdf_1_2345.pdf

$url = 'https://files.example.com/pdf/1/2345.pdf'; 
$parse = parse_url($url); 

//get path, remove first slash 
//$path: pdf/1/2345.pdf 
$path = substr($parse['path'],1); 

//result becomes: pdf_1_2345.pdf 
$result = str_replace('/','_',$path); 

编辑:最好的办法是存储远程文件的URL数据库中,它的散列值(使用MD5或类似的)并以本地名称保存文件,并将该散列值存储在数据库中。

这是你最好的选择,这样你总能知道哪个远程文件对应你的本地文件,反之亦然,你不需要在本地处理文件名,因为它们可以是任何你想要的只要你让他们检查唯一性)

Database Table: 
-------------------- 
| id | remote_url     | local_name  | 
----------------------------------------------------- 
| 1 | http://example/.../123.pdf | sdflkfd..dl.pdf| 

你明白了。

+0

str_replace()是不可逆的,但它是一个有效的解决方案。我不知道谁是第一个,所以+1。 – donquixote

+0

如果你喜欢我的回答,请接受。 –

+0

哦我看到,对于可逆的,只需使用一个唯一的字符串而不是_ ..,如果该文件名中存在唯一的字符串,则会自动选择另一个字符串。选择了类似_ = DIR = _的东西,我确定没有文件名会有:))但它是一个有效的名称。 –

0

您可以使用此功能,它用下划线替换所有目录分隔符。

function secureFilePath($str) 
{ 
    $str = str_replace('/', '_', $str); 
    $str = str_replace('\\', '_', $str); 
    $str = str_replace(DIRECTORY_SEPARATOR, '_', $str); // In case it does not equal the standard values 
    return $str; 
}