php - 验证 Windows 文件名

标签 php regex windows filenames

如何确定给定的字符串是否是有效的 Windows 文件名?我正在考虑一些函数,我可以提供一个字符串并返回一个 bool 值。它应该检查不允许的字符 (<>:"/\|?*) 和保留字(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

最佳答案

这是关于 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>

关于php - 验证 Windows 文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13740661/

相关文章:

使用 cPanel 运行 CentOS 的 VPS 服务器上的 PHP CLI "Out of memory"错误

php - Yii2 Gridview 不分页显示所有记录

php - 使用 php curl 获取 outlook 通讯簿列表?

javascript - 将 Whatsapp Markdown 转换为 HTML 标签

c++ - 为什么WNetAddConnection2调用WNetCancelConnection2成功后还是返回1219?

php - 如何修复MySql异常访问被拒绝用户 'root' @'localhost'(使用密码: YES)

regex - 跳过前导和尾随空白

regex - 在 R 中使用正则表达式提取某些符号之间的文本

windows - Pycharm GitHub 'Push failed: fatal: Authentication failed'

windows - 如何在 WP8.1 中防止 Facebook 连接上的 "You have already authorized this app"消息?