如何确定给定字符串是否为有效的Windows文件名?我正在考虑一些函数,我可以给一个字符串,并返回一个布尔值。它应该检查不允许的字符(<>:“/ \ |?*)和保留字(CON,PRN等等)。
isValidWindowsFilename('readme.txt'); // true
isValidWindowsFilename('foo/bar'); // false
isValidWindowsFilename('CON'); // false
我找到了一个MSDN参考,准确描述了什么是有效的:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
我也为Java找到了同样的问题,答案可以满足我的需要,除了它是Java而不是PHP:Validate a file name on Windows
答案 0 :(得分:7)
这是the Java question的答案,移植到PHP。
/**
* @param string $filename
* @return boolean Whether the string is a valid Windows filename.
*/
function isValidWindowsFilename($filename) {
$regex = <<<'EOREGEX'
~ # start of regular expression
^ # Anchor to start of string.
(?! # Assert filename is not: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])
(\.[^.]*)? # followed by optional extension
$ # and end of string
) # End negative lookahead assertion.
[^<>:"/\\|?*\x00-\x1F]* # Zero or more valid filename chars.
[^<>:"/\\|?*\x00-\x1F\ .] # Last char is not a space or dot.
$ # Anchor to end of string.
#
# tilde = end of regular expression.
# i = pattern modifier PCRE_CASELESS. Make the match case insensitive.
# x = pattern modifier PCRE_EXTENDED. Allows these comments inside the regex.
# D = pattern modifier PCRE_DOLLAR_ENDONLY. A dollar should not match a newline if it is the final character.
~ixD
EOREGEX;
return preg_match($regex, $filename) === 1;
}
请注意,此函数不会对文件名的长度施加任何限制,但实际文件名可能会限制为260或32767个字符,具体取决于平台。
这是验证其正确性的一些测试代码。
$tests = array(
// Valid filenames
'readme.txt' => true,
'foo.AUX' => true,
'foo.AUX.txt' => true,
'.gitignore' => true, // starting with a period is ok.
// Invalid filenames
'x<y' => false, // less than not allowed.
'x>y' => false, // greater than not allowed.
'q: why not.txt' => false, // colon not allowed.
'He said "hi".doc' => false, // double quote not allowed.
'foo/bar' => false, // Forward slash not allowed.
'foo\\bar' => false, // Backslash not allowed.
'cat readme | backup' => false, // vertical bar (pipe) not allowed.
'ls foo?.rtf' => false, // question mark not allowed
'ls foo*.rtf' => false, // asterisk not allowed
"null\0char" => false, // null character not allowed
'.' => false, // must not end in period
'..' => false, // must not end in period
'period.' => false, // must not end in period
'space ' => false, // must not end with space
// Do not use the following reserved device names for the name of a file:
// CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
// Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended.
'CON' => false,
'prn.txt' => false,
'LPT9.php' => false,
);
// Disallow characters whose integer representations are in the range from 1 through 31
for ($i = 1; $i <= 31; $i++) {
$tests[chr($i)] = false;
}
?>
<style>
.pass {
background-color: #efe;
}
.fail {
background-color: #fee;
}
</style>
<table>
<thead><tr><th>filename</th><th>expected</th><th>actual</th></tr></thead>
<tbody>
<? foreach ($tests as $filename => $expected) {
$actual = isValidWindowsFilename($filename);
?>
<tr><td><?=htmlentities($filename)?></td><td><?= $expected ? 'valid' : 'invalid' ?></td><td class="<?= $expected === $actual ? 'pass' : 'fail' ?>"><?= $actual ? 'valid' : 'invalid' ?></td></tr>
<?
} ?>
</tbody>
</table>