Checking for relative vs absolute paths/URLs in PHP
Asked Answered
O

8

14

I need to implement functions to check whether paths and urls are relative, absolute, or invalid (invalid syntactically- not whether resource exists). What are the range of cases I should be looking for?

function check_path($dirOrFile) {
    // If it's an absolute path: (Anything that starts with a '/'?)
        return 'absolute';
    // If it's a relative path: 
        return 'relative';
    // If it's an invalid path:
        return 'invalid';
}

function check_url($url) {
    // If it's an absolute url: (Anything that starts with a 'http://' or 'https://'?)
        return 'absolute';
    // If it's a relative url:
        return 'relative';
    // If it's an invalid url:
        return 'invalid';
}
Obturate answered 12/9, 2011 at 18:33 Comment(3)
nashruddin.com/… take the results of the function detailed in that link and compare the before/after results. If it's changed, then you probably had a relative urlSubtractive
<ocd>You forgot closing single-quote in the return values.</ocd>Lavernalaverne
@Marc B- While that link has some useful parts, it won't work for me as is, esp if I don't know what the base of the url being passed to me will be- I won't be able to match it...Obturate
E
11

Use:

function isAbsolute($url) {
  return isset(parse_url($url)['host']);
}

Explanation:

If the host is set, the path is absolute.

For example:

$test = [
'/link?param=1'=>parse_url('/assa?ass'),
'//aaa.com/link?param=1'=>parse_url('//assa?ass'),
'http://aaa.com/link?param=1'=>parse_url('http://as.plassa?ass')
];
var_export($test);

/* Output:
[
  "/link?param=1" => array:2 [▼ // Not absolute
    "path" => "/assa"
    "query" => "ass"
  ]
  "//aaa.com/link?param=1" => array:2 [▼ // Absolute because of host
    "host" => "assa"
    "query" => "ass"
  ]
  "http://aaa.com/link?param=1" => array:3 [▼ // Absolute because of host
    "scheme" => "http"
    "host" => "as.plassa"
    "query" => "ass"
  ]
]
*/
Erysipeloid answered 30/9, 2020 at 9:54 Comment(1)
It would be nice to mention the minimum PHP version for thisFilberte
C
5

Absolute Paths and URLs

You are correct, absolute URLs in Linux must start with /, so checking for a slash in the start of the path will be enough.

For URLs you need to check for http:// and https://, as you wrote, however, there are more URLs starting with ftp://, sftp:// or smb://. So it is very depending on what range of uses you want to cover.

Invalid Paths and URLs

Assuming you are referring to Linux, the only chars that are forbidden in a path are / and \0. This is actually very filesystem dependent, however, you can assume the above to be correct for most uses.

In Windows it is more complicated. You can read about it in the Path.GetInvalidPathChars Method documentation under Remarks.

URLs are more complicated than Linux paths as the only allowed chars are A-Z, a-z, 0-9, -, ., _, ~, :, /, ?, #, [, ], @, !, $, &, ', (, ), *, +, ,, ; and = (as described in another answer here).

Relative Paths and URLs

In general, paths and URLs which are neither absolute nor invalid are relative.

Cornetist answered 12/9, 2011 at 19:13 Comment(5)
checking for a leading slash is not enough if you expect your PHP scripts to be portable to other platforms - absolute paths on Windows may start with a backslash or "C:\" ... I came up with the following (Preg) regular expression: /^(?:\/|\\|\w\:\\).*$/ - this will match "/file", "\file", "c:\file", but not "file" or "path/file" etc.Cactus
Actually, I remember writing a filename that had a \0 in it on Linux once, on Ext3 IIRC (just for fun). Also \n in a filename works, these two things can break 99% of scripts (not to mention a half of them already break if paths have spaces lol).Zak
Hey @mindplay.dk, your regex doesn't work for C:/. But it does work for C:\. Now in Windows, C:/ paths are legitimate as well! Any ideas how to fix?Hylophagous
I added an extra optional to fix: ^(?:\/|\\|\w\:\\|\w\:\/).*$. It now recognises C:/.Hylophagous
Since trying to make it work on PHP, due to the way PHP weirdly escapes backslashes, the regex has to be converted to ^(?:\/|\\\\|\w:\\\\|\w:\/).*$/Hylophagous
L
4

From Symfony FileSystem component to check if a path is absolute:

public function isAbsolutePath($file)
{
    return strspn($file, '/\\', 0, 1)
        || (strlen($file) > 3 && ctype_alpha($file[0])
            && substr($file, 1, 1) === ':'
            && strspn($file, '/\\', 2, 1)
        )
        || null !== parse_url($file, PHP_URL_SCHEME)
    ;
}
Lidda answered 9/11, 2016 at 17:42 Comment(0)
P
4

Since I cannot comment on answers because of my poor reputation I have to respond to ymakux answer with the function that he copied from Drupal library.

I am using this function and I have found out that urls with query part (text after ? symbol) which contains | symbol will be evaluated to false

for example:

https://example.com/image.jpeg?fl=res,749,562,3|shr,,20|jpg,90

Will be evaluated to false.

All you have to do is add

\|

To query part of the regex so the function looks like:

public static function isAbsoluteUrl($url)
    {
        $pattern = "/^(?:ftp|https?|feed)?:?\/\/(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*
        (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@)?(?:
        (?:[a-z0-9\-\.]|%[0-9a-f]{2})+|(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]))(?::[0-9]+)?(?:[\/|\?]
        (?:[\w#!:\.\?\+\|=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})*)?$/xi";

        return (bool) preg_match($pattern, $url);
    }

Hope it helps someone :)

Pyatt answered 19/7, 2017 at 9:50 Comment(1)
Now for the hard part... try getting that fix into Drupal :)Chiasmus
K
3

This function is taken from Drupal

public function is_absolute($url)
{
    $pattern = "/^(?:ftp|https?|feed):\/\/(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*
    (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@)?(?:
    (?:[a-z0-9\-\.]|%[0-9a-f]{2})+|(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]))(?::[0-9]+)?(?:[\/|\?]
    (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})*)?$/xi";

    return (bool) preg_match($pattern, $url);
}
Kordula answered 25/9, 2016 at 0:47 Comment(0)
P
3

If you already know that the URL is well formed:

if(strpos($uri,'://')!==false){
    //protocol: absolute url
}elseif(substr($uri,0,1)=='/'){
    //leading '/': absolute to domain name (half relative)
}else{
    //no protocol and no leading slash: relative to this page
}
Perpetrate answered 25/7, 2019 at 10:39 Comment(2)
Is substr($uri,0,1) != '/ supposed to be substr($uri,0,1) == '/?Oldster
yes @ChrisHappy , the strange is some people flagged up with that typo :| maybe with the comments they fixed itPerpetrate
A
2

I've recently started a composer package that might be useful for checking wether URL's are relative / absolute (and more, ofcourse).

Check out the repository here: https://github.com/Enrise/UriHelper Or the composer Packagists package here: https://packagist.org/packages/enrise/urihelper

Some examples:

$uri = new \Enrise\Uri('http://usr:[email protected]:81/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment');
echo $uri->getScheme(); // http
echo $uri->getUser(); // usr
echo $uri->getPass(); // pss
echo $uri->getHost(); // example.com
echo $uri->getPort(); // 81
echo $uri->getPath(); // /mypath/myfile.html
echo $uri->getQuery(); // a=b&b[]=2&b[]=3
echo $uri->getFragment(); // myfragment
echo $uri->isSchemeless(); // false
echo $uri->isRelative(); // false

$uri->setScheme('scheme:child:scheme.VALIDscheme123:');
$uri->setPort(null);

echo $uri->getUri(); //scheme:child:scheme.VALIDscheme123:usr:[email protected]/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment
Alibi answered 21/4, 2015 at 9:12 Comment(0)
S
0

My grain of salt based on @CIRCLE answer (Symfony FileSystem Component that checks file paths):

public function is_absolute_url( $url ) {
    if ( substr( $url, 0, 1 ) === '/' ||
        // minimun absolute url lenght 5: a://a.
        strlen( $url ) < 5
    ) {
        return false;
    }

    // chars before the first '://' in the URL are only alphabetic letters?
    $scheme = strtok( $url, '://' );
    if ( ! $scheme || // no scheme found.
        ! ctype_alpha( $scheme ) // scheme with only alphabetic letters.
    ) {
        return false;
    }

    // confirm URI has a valid scheme.
    return null !== parse_url( $url, PHP_URL_SCHEME );
}
Scrobiculate answered 17/1 at 20:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.