402

I want to create a directory if it does not exist already.

Is using the is_dir function enough for that purpose?

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

Or should I combine is_dir with file_exists?

if ( !file_exists( $dir ) && !is_dir( $dir ) ) {
    mkdir( $dir );       
} 
Thomanski
  • 5
  • 2
Peter
  • 6,147
  • 7
  • 25
  • 15
  • 18
    @IvoRenkema PHP also supports `or`/`and` besides `||`/`&&`. – Camilo Martin Apr 19 '13 at 18:48
  • 2
    Operator `&&` is unuseful here, because, if file doesn't exist (`!file_exists($dir) == true`), for sure it is not a directory. And if file exists, `!is_dir($dir)` will not be checked, because `!file_exists($dir)` will return `false` and `&&` operator is [short-circuit](http://php.net/manual/en/language.operators.logical.php). – Boolean_Type Mar 08 '16 at 10:05
  • 6
    In my view, the operator should be OR. – Mojtaba Aug 29 '16 at 17:20
  • with && this works perfectly for me – FABBRj Feb 04 '20 at 11:50
  • 4
    It should be `if ( !file_exists( $dir ) || !is_dir( $dir) ) { mkdir($dir); }` If you put &&, will not create the directory if has a file with the same name of directory. – lipinf Sep 23 '20 at 19:35

12 Answers12

264

Both would return true on Unix systems - in Unix everything is a file, including directories. But to test if that name is taken, you should check both. There might be a regular file named 'foo', which would prevent you from creating a directory name 'foo'.

Marc B
  • 356,200
  • 43
  • 426
  • 500
155
$filename = "/folder/" . $dirname . "/";

if (file_exists($filename)) {
    echo "The directory $dirname exists.";
} else {
    mkdir("folder/" . $dirname, 0755);
    echo "The directory $dirname was successfully created.";
    exit;
}
Jon Winstanley
  • 23,010
  • 22
  • 73
  • 116
Maher
  • 1,599
  • 1
  • 9
  • 2
  • 15
    considering it takes post input and uses it as-is, plus makes 0777 dir, prolly not that safe at all ;P – sEver Aug 20 '13 at 16:45
  • 2
    More seriously, $dirname could be sanitized and permission could be set to 0755. Add to that some .htaccess directives. There's some further recommendations over at OWASP: https://www.owasp.org/ – James P. Aug 24 '13 at 05:21
  • `# 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 ForceType none Header unset Content-Disposition # 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` – James P. Aug 24 '13 at 05:23
  • 766 i think will be ok for a public folder since anyone can access and write but noone can delete – themhz Nov 20 '13 at 14:56
  • 10
    When you use `mkdir` - why didn't you just pass '$filename'? – Howdy_McGee Jan 14 '14 at 19:06
  • Because this answer is stupid altogether and wrong on every level. It checks if different file exists than the directory it creates (it checks at / instead of current directory). – p0358 Mar 20 '19 at 19:03
26

I think realpath() may be the best way to validate if a path exist http://www.php.net/realpath

Here is an example function:

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

Short version of the same function

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

Output examples

<?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) "/"

Usage

<?php

$folder = '/foo/bar';

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

mkdir($folder);
// Continue do stuff
inckie
  • 191
  • 3
  • 12
  • 2
    For anyone who comes across this, I believe that realpath caches folders when it runs, so if it's run once, then the folder is removed after that, it may not return false if run again. – Jase Nov 29 '15 at 03:12
  • 2
    so does file_exists though – Sebas Feb 10 '16 at 04:12
7

Second variant in question post is not ok, because, if you already have file with the same name, but it is not a directory, !file_exists($dir) will return false, folder will not be created, so error "failed to open stream: No such file or directory" will be occured. In Windows there is a difference between 'file' and 'folder' types, so need to use file_exists() and is_dir() at the same time, for ex.:

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
  • 1,146
  • 3
  • 13
  • 40
5

I had the same doubt, but see the PHP docu:

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

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

You will see that is_dir() has both properties.

Return Values is_dir Returns TRUE if the filename exists and is a directory, FALSE otherwise.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
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);
}
rons
  • 31
  • 1
  • 1
    You can check on the full path and if it doesn't exist create it with mkdir recursive: if (!file_exists($filename2)) { mkdir($filename2, 0777, true); } Also, you're code will never create the full path if $filename doesn't exist... – Niels R. Dec 30 '13 at 18:38
  • This code-only answer seems to be drifting away from the scope of the question (doesn't this answer just repeat what earlier answers already said?) and should include some plain-speak that explains the snippet. – mickmackusa Oct 12 '20 at 23:05
3
$save_folder = "some/path/" . date('dmy');

if (!file_exists($save_folder)) {
   mkdir($save_folder, 0777);
}
hour man
  • 33
  • 7
2

This is an old, but still topical question. Just test with the is_dir() or file_exists() function for the presence of the . or .. file in the directory under test. Each directory must contain these files:

is_dir("path_to_directory/.");    
RobC
  • 22,977
  • 20
  • 73
  • 80
djordje
  • 21
  • 2
1

Well instead of checking both, you could do if(stream_resolve_include_path($folder)!==false). It is slower but kills two birds in one shot.

Another option is to simply ignore the E_WARNING, not by using @mkdir(...); (because that would simply waive all possible warnings, not just the directory already exists one), but by registering a specific error handler before doing it:

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();
Community
  • 1
  • 1
Sebas
  • 21,192
  • 9
  • 55
  • 109
1

This is how I do

if(is_dir("./folder/test"))
{
  echo "Exist";
}else{
  echo "Not exist";
}
  • 3
    When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps, particularly for a question that already has an accepted answer. See: [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). – David Buck Nov 30 '19 at 20:26
0

A way to check if a path is directory can be following:

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

NOTE: It will return false for non-existant path too, but works perfectly for UNIX/Windows

Máxima Alekz
  • 572
  • 10
  • 23
0

i think this is fast solution for dir check.

$path = realpath($Newfolder);
if (!empty($path)){
   echo "1";
}else{
   echo "0";
}
Umut Can Arda
  • 81
  • 1
  • 8