Как проверить, существует ли каталог? «Is_dir», «file_exists» или оба?

329

Я хочу создать каталог, если он еще не существует.

Пользуется is_dirдостаточно для этой цели?

if ( !is_dir( $dir ) ) {
    mkdir( $dir );       
}

Или я должен сочетаться is_dirс file_exists?

if ( !file_exists( $dir ) && !is_dir( $dir ) ) {
    mkdir( $dir );       
} 
Питер
источник
3
Логический оператор OR должен быть AND, а в PHP он записывается как &&
Ivo Renkema
15
@IvoRenkema PHP также поддерживает or/ andпомимо ||/ &&.
Камило Мартин
1
Оператор &&здесь бесполезен, потому что, если файл не существует ( !file_exists($dir) == true), он точно не является каталогом. И если файл существует, !is_dir($dir)проверяться не будет, так !file_exists($dir)как вернется falseи &&оператор замкнут .
Boolean_Type
4
На мой взгляд, оператор должен быть ИЛИ.
Мойтаба
с && это прекрасно работает для меня
FABBRj

Ответы:

220

Оба возвращают true в системах Unix - в Unix все является файлом, включая каталоги. Но чтобы проверить, занято ли это имя, вы должны проверить оба. Там может быть обычный файл с именем 'foo', который не позволит вам создать каталог с именем 'foo'.

Марк Б
источник
37
не забудьте проверить, если is_writable также
Drewdin
10
@ Дрюдин, ты бы хотел проверить родителей is_writable, не так ли?
Мэтью Шарли
133
$dirname = $_POST["search"];
$filename = "/folder/" . $dirname . "/";

if (!file_exists($filename)) {
    mkdir("folder/" . $dirname, 0777);
    echo "The directory $dirname was successfully created.";
    exit;
} else {
    echo "The directory $dirname exists.";
}
Maher
источник
46
Очень много, что говорит эхо ...
Кей - SE зла
13
учитывая, что он принимает пост-ввод и использует его как есть, плюс делает 0777 dir, совсем не безопасно, P
sEver
2
Более серьезно, $ dirname можно очистить, а разрешение можно установить равным 0755. Добавьте к этому некоторые директивы .htaccess. На OWASP есть еще несколько рекомендаций: owasp.org
Джеймс П.
# The following directives force the content-type application/octet-stream # and force browsers to display a download dialog for non-image files. # This prevents the execution of script files in the context of the website: #ForceType application/octet-stream Header set Content-Disposition attachment <FilesMatch "(?i)\.(gif|jpe?g|png)$"> ForceType none Header unset Content-Disposition </FilesMatch> # The following directive prevents browsers from MIME-sniffing the content-type. # This is an important complement to the ForceType directive above: Header set X-Content-Type-Options nosniff
Джеймс П.
7
Когда вы используете mkdir- почему вы просто не передали '$ filename'?
Howdy_McGee
17

Я думаю, что realpath () может быть лучшим способом проверки, если путь существует http://www.php.net/realpath

Вот пример функции:

<?php
/**
 * Checks if a folder exist and return canonicalized absolute pathname (long version)
 * @param string $folder the path being checked.
 * @return mixed returns the canonicalized absolute pathname on success otherwise FALSE is returned
 */
function folder_exist($folder)
{
    // Get canonicalized absolute pathname
    $path = realpath($folder);

    // If it exist, check if it's a directory
    if($path !== false AND is_dir($path))
    {
        // Return canonicalized absolute pathname
        return $path;
    }

    // Path/folder does not exist
    return false;
}

Короткая версия той же функции

<?php
/**
 * Checks if a folder exist and return canonicalized absolute pathname (sort version)
 * @param string $folder the path being checked.
 * @return mixed returns the canonicalized absolute pathname on success otherwise FALSE is returned
 */
function folder_exist($folder)
{
    // Get canonicalized absolute pathname
    $path = realpath($folder);

    // If it exist, check if it's a directory
    return ($path !== false AND is_dir($path)) ? $path : false;
}

Примеры вывода

<?php
/** CASE 1 **/
$input = '/some/path/which/does/not/exist';
var_dump($input);               // string(31) "/some/path/which/does/not/exist"
$output = folder_exist($input);
var_dump($output);              // bool(false)

/** CASE 2 **/
$input = '/home';
var_dump($input);
$output = folder_exist($input);         // string(5) "/home"
var_dump($output);              // string(5) "/home"

/** CASE 3 **/
$input = '/home/..';
var_dump($input);               // string(8) "/home/.."
$output = folder_exist($input);
var_dump($output);              // string(1) "/"

использование

<?php

$folder = '/foo/bar';

if(FALSE !== ($path = folder_exist($folder)))
{
    die('Folder ' . $path . ' already exist');
}

mkdir($folder);
// Continue do stuff
inckie
источник
2
Для тех, кто сталкивается с этим, я полагаю, что realpath кэширует папки при запуске, поэтому, если он запускается один раз, после этого папка удаляется, и может не возвращать false при повторном запуске.
Jase
2
как и file_exists
Sebas
7

Второй вариант в сообщении с вопросом не подходит, потому что, если у вас уже есть файл с таким же именем, но это не каталог, !file_exists($dir)он вернется false, папка не будет создана, поэтому "failed to open stream: No such file or directory"произойдет ошибка . В Windows есть разница между типами «файл» и «папка», поэтому необходимо использовать file_exists()и is_dir()одновременно, например:

if (file_exists('file')) {
    if (!is_dir('file')) { //if file is already present, but it's not a dir
        //do something with file - delete, rename, etc.
        unlink('file'); //for example
        mkdir('file', NEEDED_ACCESS_LEVEL);
    }
} else { //no file exists with this name
    mkdir('file', NEEDED_ACCESS_LEVEL);
}
Boolean_Type
источник
3
$year = date("Y");   
$month = date("m");   
$filename = "../".$year;   
$filename2 = "../".$year."/".$month;

if(file_exists($filename)){
    if(file_exists($filename2)==false){
        mkdir($filename2,0777);
    }
}else{
    mkdir($filename,0777);
}
РОНС
источник
1
Вы можете проверить полный путь и, если он не существует, создать его с помощью mkdir recursive: if (! File_exists ($ filename2)) {mkdir ($ filename2, 0777, true); } Кроме того, ваш код никогда не создаст полный путь, если $ filename не существует ...
Нильс Р.
3
$save_folder = "some/path/" . date('dmy');

if (!file_exists($save_folder)) {
   mkdir($save_folder, 0777);
}
часовой человек
источник
3
Установка chmod 777 никогда не бывает хорошей идеей. 755 достаточно для папок.
Oldskool
2

добавить истину после 0777

<?php
    $dirname = "small";
    $filename = "upload/".$dirname."/";

    if (!is_dir($filename )) {
        mkdir("upload/" . $dirname, 0777, true);
        echo "The directory $dirname was successfully created.";
        exit;
    } else {
        echo "The directory $dirname exists.";
    }
     ?>
Суджит Кумар
источник
1

Ну, вместо того, чтобы проверить оба, вы могли бы сделать if(stream_resolve_include_path($folder)!==false). Это медленнее, но убивает двух птиц за один выстрел.

Другой вариант - просто игнорировать E_WARNING, не используя @mkdir(...);(потому что это просто отменит все возможные предупреждения, не только каталог уже существует), но и зарегистрирует определенный обработчик ошибок, прежде чем делать это:

namespace com\stackoverflow;

set_error_handler(function($errno, $errm) { 
    if (strpos($errm,"exists") === false) throw new \Exception($errm); //or better: create your own FolderCreationException class
});
mkdir($folder);
/* possibly more mkdir instructions, which is when this becomes useful */
restore_error_handler();
Sebas
источник
1

У меня было такое же сомнение, но посмотрите документ PHP:

https://www.php.net/manual/en/function.file-exists.php

https://www.php.net/manual/en/function.is-dir.php

Вы увидите, что is-dir обладает обоими свойствами.

Возвращаемые значения is_dir Возвращает TRUE, если имя файла существует и является каталогом, иначе FALSE.

Бренда Янела Конзи
источник
1

Это старый, но все еще актуальный вопрос. Просто проверьте с помощью функции is_dir()или file_exists()наличие файла .или ..в тестируемом каталоге. Каждый каталог должен содержать эти файлы:

is_dir("path_to_directory/.");    
Джордже
источник
0

Вот как я делаю

if(is_dir("./folder/test"))
{
  echo "Exist";
}else{
  echo "Not exist";
}
Джетро Бернардо
источник
При ответе на старый вопрос ваш ответ был бы гораздо более полезным для других пользователей StackOverflow, если бы вы включили некоторый контекст для объяснения того, как ваш ответ помогает, особенно для вопроса, на который уже есть принятый ответ. Смотрите: Как мне написать хороший ответ .
Дэвид Бак
0

Способ проверить, является ли путь каталогом, может быть следующим:

function isDirectory($path) {
    $all = @scandir($path);
    return $all !== false;
}

ПРИМЕЧАНИЕ: он вернет false и для несуществующего пути, но отлично работает для UNIX / Windows

Максима Алекз
источник