【问题标题】:Validate Windows filename验证 Windows 文件名
【发布时间】:2023-03-09 10:09:01
【问题描述】:

如何确定给定字符串是否是有效的 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

【问题讨论】:

    标签: php regex windows filenames


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-19
      • 2023-02-22
      • 2021-02-25
      • 1970-01-01
      • 2011-10-31
      • 1970-01-01
      • 2012-01-30
      相关资源
      最近更新 更多