Как определить, является ли данная строка допустимым именем файла 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: проверка имени файла в Windows
Вот ответ на вопрос Java , перенесенный на 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>