17

I'm using:

$domain = $_SERVER['HTTP_HOST'];
$path = $_SERVER['SCRIPT_NAME'];
$themeurl = $domain . $path;

But this of course gives the full URL. Instead I need the full URL minus the current file and up one directory and minus the trailing slash.

so no matter what the browser URL domain is eg localhost, https://, http://, etc that the full real (bypassing any mod rewrites) URL path of the parent directory is given without a trailing slash.

How is this done? Safely so no XSS as I guess (from reading) using anything but 'SCRIPT_NAME' has such risk.. not sure though ofc.. just been reading a ton trying to figure this out.

examples: if given:

https://stackoverflow.com/questions/somequestions/index.php

need:

https://stackoverflow.com/questions

without the trailing slash.

and should also work for say:

http://localhost/GetSimple/admin/load.php

to get

http://localhost/GetSimple

which is what I'm trying to do.

Thank you.



Edit: Here's the working solution I used:
$url  = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
$url .= $_SERVER['SERVER_NAME'];
$url .= htmlspecialchars($_SERVER['REQUEST_URI']);
$themeurl = dirname(dirname($url)) . "/theme";

it works perfectly.

Rocket Spaceman
  • 343
  • 1
  • 4
  • 12
  • realpath($_SERVER["DOCUMENT_ROOT"] . "/../"); define('SITE_PATH', realpath(dirname(__FILE__))); define('UPPER_PATH', dirname(SITE_PATH)); realpath(dirname(__FILE__) . "/../"); $url_folder = substr(substr($_SERVER["REQUEST_URI"],1), 0, strpos(substr($_SERVER["REQUEST_URI"],1), "/")); $_SERVER['REQUEST_URL'] $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URL"] . "/../" a ton of different stuff.. I'm new to PHP and doing the best with what I've got so far. – Rocket Spaceman Feb 27 '13 at 11:05
  • As hek2mgl mentioned, it's correct, and a more dynamic approach would be dirname(dirname($_SERVER['REQUEST_URI'])); – Sid Feb 27 '13 at 11:10
  • dirname x2 doesn't work... I've tried it Sid and pasted the results given... it outputs the directory tree twice in the URL string. – Rocket Spaceman Feb 27 '13 at 11:34
  • Why that htmlspecialchars() @RocketSpaceman ? – Dario Ferrer Apr 21 '20 at 01:06

7 Answers7

35

Thats easy - using the function dirname twice :)

echo dirname(dirname('https://stackoverflow.com/questions/somequestions/index.php'));

Also note @Sid's comment. When you you need the full uri to the current script, with protocol and server the use something like this:

$url  = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
$url .= $_SERVER['SERVER_NAME'];
$url .= $_SERVER['REQUEST_URI'];

echo dirname(dirname($url));
Sid
  • 854
  • 9
  • 23
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • @hek2mgl that does not work... that outputed: http://localhost/GetSimple/theme/FoundationNation/localhost/GetSimple/FoundationNation/images/foundation/plus-toggle-2.png... so no there's a problem with your solution. – Rocket Spaceman Feb 27 '13 at 11:10
  • @YogeshSuthar his solution doesn't work Yogesh... see my question and try it... $domain = $_SERVER['HTTP_HOST']; $path = $_SERVER['SCRIPT_NAME']; $themeurl = dirname(dirname($domain . $path)); doesn't work – Rocket Spaceman Feb 27 '13 at 11:12
  • 1
    Try using dirname(dirname($_SERVER['REQUEST_URI'])); I've posted it as an answer. It's working for me, should work for you too. – Sid Feb 27 '13 at 11:13
  • Yea... this doesn't work guys.. I'm localhost trying every option given so far. Again I need to work with the SCRIPT_NAME, remove the page and queries, move up one directory (not down from root) and then remove the trailing slash.... – Rocket Spaceman Feb 27 '13 at 11:31
  • I have `http://localhost/a/b/c/test.php` for testing .. It outputs : `http://localhost:80/a/b`. This should be what you requested. Isn't it? – hek2mgl Feb 27 '13 at 11:36
  • @hek2mgl Not exactly no.. if you have http : / / localhost/a/b/c/test.php I'd need http : / / localhost/a/b – Rocket Spaceman Feb 27 '13 at 11:44
  • without the port? without the protocol? without both? Please read your question, there you say you need the 'http://' in front of. Just give me a schema and I can finally answer the question – hek2mgl Feb 27 '13 at 11:45
  • protocol (+plus) domain (+plus) entire directory tree (-minus) one directory (-minus) ending slash – Rocket Spaceman Feb 27 '13 at 11:50
  • the port number... eg need `http://localhost/a/b` or `http://example.com/a/b` or `https://example.org/a/b` etc – Rocket Spaceman Feb 27 '13 at 11:58
  • Then please think **5 seconds** which of the 5 line example you'll have to remove. (although I would not remove the port) .. SO is not to prevent you from thinking at least a little bit for yourself. This site is just to *help* you – hek2mgl Feb 27 '13 at 11:59
  • 1
    Edited hek2mgl's post. This is without the port no. Hope this works out for you. – Sid Feb 27 '13 at 12:01
  • Thanks, no need to be nasty.. I explained earlier that I'm new to PHP and when trying your example I wasn't sure if SERVER_NAME was only the name and not the suffix (which I would need) since I am on localhost testing this. – Rocket Spaceman Feb 27 '13 at 12:03
  • Thats not about nasty.. I like helping. But sometimes its better to think, try, think, try before post.. and its better to learn the basics of programming, like variables, functions, classes, *manuals* before thinking about XSS attack prevention ;) believe me, I just want to help. the dirname() tip is good! prevents you from getting *nasty* code... good luck! ;) – hek2mgl Feb 27 '13 at 12:07
  • "Then please think 5 seconds which of the 5 line example you'll have to remove. (although I would not remove the port) .. SO is not to prevent you from thinking at least a little bit for yourself. This site is just to help you" I'm not disagreeing about thinking.. but obviously if I was sure of something I'd try it. Thank for help but it'd be nice if you helped without making assumptions on what I have done or haven't done. And alluding to me not "thinking" is rude.. no way to justify that type of comment. But thanks for a working solution anyway. – Rocket Spaceman Feb 27 '13 at 12:11
  • Note that using the `HTTP_X_FORWARDED_HOST` header is a security hole. It can be easily spoofed. – hek2mgl Dec 06 '13 at 10:26
  • @hek2mgl please explain what kind of security hole it is – Timo Huovinen Dec 06 '13 at 11:18
  • Better to use SCRIPT_NAME instead of REQUEST_URI since dirname() will fail with the latter if you have query strings with paths. – guidod Jan 28 '16 at 19:19
3

I have more simple syntax to get parent addres with port and url lets try my code

dirname($_SERVER['PHP_SELF'])

with this code you can got a direct parent of adres if you want to 2x roll back directory you can looping

dirname(dirname($_SERVER['PHP_SELF']))

dirname is fungtion to get parent addrest web and $_SERVER['PHP_SELF'] can showing current addres web.

thakyou Sir https://stackoverflow.com/users/171318/hek2mgl

Community
  • 1
  • 1
2

I do not suggest using dirname()as it is for directories and not for URIs. Examples:

  • dirname("http://example.com/foo/index.php") returns http://example.com/foo
  • dirname("http://example.com/foo/") returns http://example.com
  • dirname("http://example.com/") returns http:
  • dirname("http://example.com") returns http:

So you have to be very carful which $_SERVER var you use and of course it works only for this specific problem. A much better general solution would be to use currentdir() on which basis you could use this to get the parent directory:

function parentdir($url) {
    // note: parent of "/" is "/" and parent of "http://example.com" is "http://example.com/"
    // remove filename and query
    $url = currentdir($url);
    // get parent
    $len = strlen($url);
    return currentdir(substr($url, 0, $len && $url[ $len - 1 ] == '/' ? -1 : $len));
}

Examples:

  • parentdir("http://example.com/foo/bar/index.php") returns http://example.com/foo/
  • parentdir("http://example.com/foo/index.php") returns http://example.com/
  • parentdir("http://example.com/foo/") returns http://example.com/
  • parentdir("http://example.com/") returns http://example.com/
  • parentdir("http://example.com") returns http://example.com/

So you would have much more stable results. Maybe you could explain why you wanted to remove the trailing slash. My experience is that it produces more problems as you are not able to differentiate between a file named "/foo" and a folder with the same name without using is_dir(). But if this is important for you, you could remove the last char.

Community
  • 1
  • 1
mgutt
  • 5,867
  • 2
  • 50
  • 77
1

This example works with ports

function full_url($s)
{
    $ssl = (!empty($s['HTTPS']) && $s['HTTPS'] == 'on') ? true:false;
    $sp = strtolower($s['SERVER_PROTOCOL']);
    $protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : '');
    $port = $s['SERVER_PORT'];
    $port = ((!$ssl && $port=='80') || ($ssl && $port=='443')) ? '' : ':'.$port;
    $host = isset($s['HTTP_HOST']) ? $s['HTTP_HOST'] : $s['SERVER_NAME'];
    return $protocol . '://' . $host . $port . $s['REQUEST_URI'];
}
$themeurl = dirname(dirname(full_url($_SERVER))).'/theme';
echo '<a href="'.htmlspecialchars($themeurl,ENT_QUOTES,'UTF-8').'">Theme URL</a>';

Source: https://stackoverflow.com/a/8891890/175071

Community
  • 1
  • 1
Timo Huovinen
  • 53,325
  • 33
  • 152
  • 143
0

I'm with hek2mgl. However, just in case the script isn't always specifically 2 directories below your target, you could use explode:

$parts = explode("/",ltrim($_SERVER['SCRIPT_NAME'],"/"));
echo $_SERVER['HTTP_HOST'] . "/" . $parts[0];
George
  • 36,413
  • 9
  • 66
  • 103
  • question... why would this $path = explode("/",$_SERVER['SCRIPT_NAME']); $themeurl = $_SERVER['HTTP_HOST'] . "/" . $path[0]; give me a result of this: http://localhost/GetSimple/theme/FoundationNation/localhost//FoundationNation/images/foundation/plus-toggle-2.png there's a double slash and it's repeating the root twice... :( – Rocket Spaceman Feb 27 '13 at 11:20
  • I've updated it my friend, please make changes. I have added an `ltrim()` into the mix – George Feb 27 '13 at 11:21
  • Thank you, but that wont work either: localhost//FoundationNation/images/prettyPhoto/default/sprite.png. See one problem is the amount of total directories can change and using explode limits me from going UP one directory and instead starts me at the root of the path, now if I don't know how many directories total their are I'm screwed... so need to work with the original full length URL.. then remove the page, any queries, one directory, and a trailing slash... that's what I've been trying so hard to do.. 3 options give so far and none of them do the trick needed yet. – Rocket Spaceman Feb 27 '13 at 11:29
0

As hek2mgl mentioned, it's correct, and a more dynamic approach would be dirname(dirname(htmlspecialchars($_SERVER['REQUEST_URI'])));.

EDIT:

$_SERVER['REQUEST_URI'] will omit the domain name. Referring @hek2mgl's post, you can echo dirname(dirname(htmlspecialchars($url)));

Sid
  • 854
  • 9
  • 23
  • Doesn't REQUEST_URI have XSS security risk? – Rocket Spaceman Feb 27 '13 at 11:32
  • XSS, yes. You can clean it up with htmlspecialchars(). I've edited the post plz check it. – Sid Feb 27 '13 at 11:37
  • this just outputs the parent directory... eg /GetSimple instead of http : / / localhost/GetSimple (I don't know how to format code in replies) but it's a start... will it work if the directory tree is much larger? – Rocket Spaceman Feb 27 '13 at 11:46
  • $_SERVER['REQUEST_URI'] will omit the domain name. You can refer @hek2mgl's edited post and add htmlspecialchars to it. I'll edit my post. – Sid Feb 27 '13 at 11:51
  • this kinda works but is missing the protocol: echo $_SERVER['HTTP_HOST'] . dirname(dirname(htmlspecialchars($_SERVER['SCRIPT_NAME']))); – Rocket Spaceman Feb 27 '13 at 11:53
-1

Here are useful commands to get the desired path:

( For example, you are executing in http:// yoursite.com/folder1/folder2/file.php)

__FILE__   (on L.Hosting)   === /home/xfiddlec/http_docs/folder1/folder2/yourfile.php
__FILE__   (on Localhost) === C:\wamp\www\folder1\folder2\yourfile.php 
$_SERVER['HTTP_HOST']     === www.yoursite.com (or without WWW)   
$_SERVER["PHP_SELF"]      === /folder1/folder2/yourfile.php
$_SERVER["REQUEST_URI"]   === /folder1/folder2/yourfile.php?var=blabla
$_SERVER["DOCUMENT_ROOT"] === /home/xfiddlec/http_docs

// BASENAME and DIRNAME (lets say,when __file__ is '/folder1/folder2/yourfile.php'
basename(__FILE__)  ==== yourfile.php
dirname(__FILE__)   ==== /folder1/folder2

Examples:

*HOME url             ( yoursite.com )

<?php echo $_SERVER['HTTP_HOST'];?>

*file's BASE url     ( yoursite.com/anyfolder/myfile.php )

<?php echo $_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']; ?>

*COMPLETE current url ( yoursite.com/anyfolder/myfile.php?action=blabla )

<?php echo $_SERVER['HTTP_HOST'].$_SERVER["REQUEST_URI"];?>

*CURRENT FOLDER's URL ( yoursite.com/anyfolder/ )

<?php echo $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']);  ?>

*To get RealPath to the file (even if it is included) (change /var/public_html to your desired root)

<?php
$cur_file=str_replace('\\','/',__FILE__); //Then Remove the root path::
$cur_file=preg_replace('/(.*?)\/var\/public_html/','',$cur_file);
?>

p.s.for wordpress, there exist already pre-defined functions to get plugins or themes url.

i.e. get plugin folder ( http://yoursite.com/wp-content/plugins/pluginName/ )
<?php echo plugin_dir_url( __FILE__ );?>
kittycat
  • 14,983
  • 9
  • 55
  • 80
T.Todua
  • 53,146
  • 19
  • 236
  • 237