Як перевірити, чи існує каталог? "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
Бульним оператором АБО має бути AND, а в PHP написано як &&
Іво Ренкема

15
@IvoRenkema PHP також підтримує or/ andкрім того ||/ &&.
Каміло Мартін

1
Оператор &&тут непридатний, тому що, якщо файл не існує ( !file_exists($dir) == true), напевно, це не каталог. І якщо файл існує, !is_dir($dir)не буде перевірятися, тому що !file_exists($dir)повернеться, falseа &&оператор коротке замикання .
Boolean_Type

4
На мою думку, оператором має бути АБО.
Мойтаба

& & це прекрасно працює для мене
FABBRj

Відповіді:


220

Обидва повернуть справжнє в системах Unix - в Unix все є файлом, включаючи каталоги. Але щоб перевірити, чи прийнято це ім’я, слід перевірити обидва. Можливо, існує звичайний файл з назвою 'foo', який би перешкоджав створенню імені каталогу 'foo'.


37
не забудьте перевірити, чи є також_записом
Древдін

10
@Drewdin, ти хотів би перевірити батьків, 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.";
}

46
Дуже багато, що говорить відлуння…
Кей - SE це зло

13
враховуючи, що він займає пост-введення та використовує його як є, плюс робить 0777 dir, proally зовсім не так безпечно; P
sEver

2
Більш серйозно, $ dirname може бути дезінфікований, а дозвіл - 0755. Додайте до цього деякі директиви .htaccess. Є кілька додаткових рекомендацій на OWASP
James P.

# 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

2
Для всіх, хто стикається з цим, я вважаю, що realpath кешує папки, коли він запускається, тому якщо він запущений один раз, то папка після цього буде видалена, вона може не повернути помилкову, якщо запустити ще раз.
Jase

2
так само є file_exists
Себас

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);
}

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: if (! File_exists ($ filename2)) {mkdir ($ filename2, 0777, true); } Крім того, ваш код ніколи не створить повний шлях, якщо $ filename не існує ...
Niels R.

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();

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 Повертає ІСТИНА, якщо ім'я файлу існує та є каталогом, ЛІЖНІ в іншому випадку.


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.