Get the full URL in PHP
Solution 1:
Have a look at $_SERVER['REQUEST_URI']
, i.e.
$actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
(Note that the double quoted string syntax is perfectly correct)
If you want to support both HTTP and HTTPS, you can use
$actual_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
Editor's note: using this code has security implications. The client can set HTTP_HOST and REQUEST_URI to any arbitrary value it wants.
Solution 2:
Short version to output link on a webpage
$url = "//{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
$escaped_url = htmlspecialchars( $url, ENT_QUOTES, 'UTF-8' );
echo '<a href="' . $escaped_url . '">' . $escaped_url . '</a>';
Here are some more details about the issues and edge cases of the //example.com/path/ format
Full version
function url_origin( $s, $use_forwarded_host = false )
{
$ssl = ( ! empty( $s['HTTPS'] ) && $s['HTTPS'] == 'on' );
$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 = ( $use_forwarded_host && isset( $s['HTTP_X_FORWARDED_HOST'] ) ) ? $s['HTTP_X_FORWARDED_HOST'] : ( isset( $s['HTTP_HOST'] ) ? $s['HTTP_HOST'] : null );
$host = isset( $host ) ? $host : $s['SERVER_NAME'] . $port;
return $protocol . '://' . $host;
}
function full_url( $s, $use_forwarded_host = false )
{
return url_origin( $s, $use_forwarded_host ) . $s['REQUEST_URI'];
}
$absolute_url = full_url( $_SERVER );
echo $absolute_url;
This is a heavily modified version of http://snipplr.com/view.php?codeview&id=2734 (Which no longer exists)
URL structure:
scheme://username:password@domain:port/path?query_string#fragment_id
The parts in bold will not be included by the function
Notes:
- This function does not include
username:password
from a full URL or the fragment (hash). - It will not show the default port 80 for HTTP and port 443 for HTTPS.
- Only tested with http and https schemes.
- The
#fragment_id
is not sent to the server by the client (browser) and will not be added to the full URL. -
$_GET
will only containfoo=bar2
for an URL like/example?foo=bar1&foo=bar2
. - Some CMS's and environments will rewrite
$_SERVER['REQUEST_URI']
and return/example?foo=bar2
for an URL like/example?foo=bar1&foo=bar2
, use$_SERVER['QUERY_STRING']
in this case. - Keep in mind that an URI =
URL + URN
, but due to popular use, URL now means both URI and URL. - You should remove
HTTP_X_FORWARDED_HOST
if you do not plan to use proxies or balancers. - The spec says that the
Host
header must contain the port number unless it is the default number.
Client (Browser) controlled variables:
-
$_SERVER['REQUEST_URI']
. Any unsupported characters are encoded by the browser before they are sent. -
$_SERVER['HTTP_HOST']
and is not always available according to comments in the PHP manual: http://php.net/manual/en/reserved.variables.php -
$_SERVER['HTTP_X_FORWARDED_HOST']
gets set by balancers and is not mentioned in the list of$_SERVER
variables in the PHP manual.
Server controlled variables:
-
$_SERVER['HTTPS']
. The client chooses to use this, but the server returns the actual value of either empty or "on". -
$_SERVER['SERVER_PORT']
. The server only accepts allowed numbers as ports. -
$_SERVER['SERVER_PROTOCOL']
. The server only accepts certain protocols. -
$_SERVER['SERVER_NAME']
. It is set manually in the server configuration and is not available for IPv6 according to kralyk.
Related:
What is the difference between HTTP_HOST and SERVER_NAME in PHP?
Is Port Number Required in HTTP "Host" Header Parameter?
https://stackoverflow.com/a/28049503/175071
Solution 3:
Examples for: https://(www.)example.com/subFolder/myfile.php?var=blabla#555
// ======= PATHINFO ====== //
$x = pathinfo($url);
$x['dirname'] 🡺 https://example.com/subFolder
$x['basename'] 🡺 myfile.php?var=blabla#555 // Unsecure!
$x['extension'] 🡺 php?var=blabla#555 // Unsecure!
$x['filename'] 🡺 myfile
// ======= PARSE_URL ====== //
$x = parse_url($url);
$x['scheme'] 🡺 https
$x['host'] 🡺 example.com
$x['path'] 🡺 /subFolder/myfile.php
$x['query'] 🡺 var=blabla
$x['fragment'] 🡺 555
//=================================================== //
//========== self-defined SERVER variables ========== //
//=================================================== //
$_SERVER["DOCUMENT_ROOT"] 🡺 /home/user/public_html
$_SERVER["SERVER_ADDR"] 🡺 143.34.112.23
$_SERVER["SERVER_PORT"] 🡺 80(or 443 etc..)
$_SERVER["REQUEST_SCHEME"] 🡺 https //similar: $_SERVER["SERVER_PROTOCOL"]
$_SERVER['HTTP_HOST'] 🡺 example.com (or with WWW) //similar: $_SERVER["SERVER_NAME"]
$_SERVER["REQUEST_URI"] 🡺 /subFolder/myfile.php?var=blabla
$_SERVER["QUERY_STRING"] 🡺 var=blabla
__FILE__ 🡺 /home/user/public_html/subFolder/myfile.php
__DIR__ 🡺 /home/user/public_html/subFolder //same: dirname(__FILE__)
$_SERVER["REQUEST_URI"] 🡺 /subFolder/myfile.php?var=blabla
parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH)🡺 /subFolder/myfile.php
$_SERVER["PHP_SELF"] 🡺 /subFolder/myfile.php
// ==================================================================//
//if "myfile.php" is included in "PARENTFILE.php" , and you visit "PARENTFILE.PHP?abc":
$_SERVER["SCRIPT_FILENAME"]🡺 /home/user/public_html/parentfile.php
$_SERVER["PHP_SELF"] 🡺 /parentfile.php
$_SERVER["REQUEST_URI"] 🡺 /parentfile.php?var=blabla
__FILE__ 🡺 /home/user/public_html/subFolder/myfile.php
// =================================================== //
// ================= handy variables ================= //
// =================================================== //
//If site uses HTTPS:
$HTTP_or_HTTPS = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!=='off') || $_SERVER['SERVER_PORT']==443) ? 'https://':'http://' ); //in some cases, you need to add this condition too: if ('https'==$_SERVER['HTTP_X_FORWARDED_PROTO']) ...
//To trim values to filename, i.e.
basename($url) 🡺 myfile.php
//excellent solution to find origin
$debug_files = debug_backtrace();
$caller_file = count($debug_files) ? $debug_files[count($debug_files) - 1]['file'] : __FILE__;
Notice ! ! !
- hashtag
#
parts were manually used in the above example just for illustration purposes, however, server-side languages (includingphp
) can't natively detect them (Only Javascript can do that, as hashtag is onlybrowser/client side
functionality ). -
DIRECTORY_SEPARATOR
returns\
for Windows-type hosting, instead of/
.
For WordPress
//(let's say, if wordpress is installed in subdirectory: http://example.com/wpdir/)
home_url() 🡺 http://example.com/wpdir/ //if is_ssl() is true, then it will be "https"
get_stylesheet_directory_uri() 🡺 http://example.com/wpdir/wp-content/themes/THEME_NAME [same: get_bloginfo('template_url') ]
get_stylesheet_directory() 🡺 /home/user/public_html/wpdir/wp-content/themes/THEME_NAME
plugin_dir_url(__FILE__) 🡺 http://example.com/wpdir/wp-content/themes/PLUGIN_NAME
plugin_dir_path(__FILE__) 🡺 /home/user/public_html/wpdir/wp-content/plugins/PLUGIN_NAME/
Solution 4:
Here's a solution using a ternary statement, keeping the code minimal:
$url = "http" . (($_SERVER['SERVER_PORT'] == 443) ? "s" : "") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
This is the smallest and easiest way to do this, assuming one's web server is using the standard port 443 for HTTPS.