Axel
Axel

Reputation: 3323

Check if string could be a path (without warning)

How can I check if a string is a valid path in PHP without warning if string isn't a valid path?

When I use file_get_contents, is_file, realpath, file_exists with a string that isn't a path I get the following warning.

"function_name()" expects parameter 1 to be a valid path, string given in [...]

So how to determine whether the string could be a valid path or not.


What the hell do you want to do? You may ask...

Well, I want to create a function like this.

funtion my_smart_function( string $path_or_content )
{
    $content = is_file_without_warning_if_not_a_valid_path( $path_or_content )
             ? file_get_contents( $path_or_content )
             :                    $path_or_content;
    // do nice stuff with my $content
}

Sometimes $path_or_content will be a valid path to a file and sometimes $path_or_content will be the content of a file by itself (eg the binary data of an image created on the fly that doesn't even have a path (at least not yet)). In the latter case all these string related functions I mentioned above (eg file_exists()) will throw a warning (see quote above).


Something I'm wondering about.
realpath('xyz') doesn't throw a warning but
realpath( file_get_contents('path/to/actual/image.jpg') ) does...

So realpath and the other functions mentioned above distinguish between a string or a string that is a valid path. So how can we do either beforehand?

Upvotes: 7

Views: 9325

Answers (4)

okainov
okainov

Reputation: 4658

file_exists does not check that path is a valid path and has undocumented behavior. In the meantime there is no function to check whether path is valid or not. Minimal check could be as suggested by Barmar: return strpos($path, "\0") === false

However usually you don't want unprintable characters in your filenames neither, so it would be quite fair assumption to just use ctype_print function before passing the path to file_exists (as suggested by Daan).

A bit of background

Even though everyone uses file_exists to check... that file exists, this function (and some others) does more than that.

To be precise, it returns null if path is not a valid path (i.e. contains \0). It's a PHP bug.

This is very confusing behavior. Even though documentation says that file_exists "Returns TRUE if the file or directory specified by filename exists; FALSE otherwise.", this is not the current implementation behavior.

As per someone's from PHP community:

No, file_exists does not test valid paths. It tests if a "file" exists. The presumption is that the path you are giving is valid, because if not then it couldn't possibly exist.

Upvotes: 0

Barmar
Barmar

Reputation: 780673

This may be a reasonable time to use the @ modifier to suppress errors.

funtion my_smart_function( string $path_or_content )
{
    $content =      @file_exists( $path_or_content )
             ? file_get_contents( $path_or_content )
             :                    $path_or_content;
}

If it's not a valid path, file_exists() will return a falsey value, and the @ will keep it from complaining about the bad string.

On Linux, the only character that's not allowed in a path is the null byte. So you could just check for this:

if (strpos($path_or_contents, "\0") === false) {
    return file_get_contents($path_or_contents);
} else {
    return $path_or_contents;
}

Upvotes: 6

Daan
Daan

Reputation: 12236

I believe this is exactly what you want. ctype_print checks if all of the characters in the provided string, are printable. If so pass it to file_exists.

function my_smart_function( $path_or_content )
{

    $content = ctype_print($path_or_content) && file_exists( $path_or_content )
             ? file_get_contents( $path_or_content )
             :                    $path_or_content;

    // do nice stuff with my $content
}

Upvotes: 4

Madhur Bhaiya
Madhur Bhaiya

Reputation: 28834

I think you missed file_exists function. From documentation:

file_exists — Checks whether a file or directory exists

bool file_exists ( string $filename )

Returns TRUE if the file or directory specified by filename exists; FALSE otherwise.

Upvotes: 0

Related Questions