Obtener la URL actual con PHP puede ser muy simple como esto:

$url = $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]

Si lo vamos a utilizar como link podríamos hacer esto:

// Nota: el resultado es protocolo agnostic
$link = $_SERVER[HTTP_HOST] . $_SERVER[REQUEST_URI];
$escaped_link = htmlspecialchars($link, ENT_QUOTES, 'UTF-8');
echo '<a href="'.$escaped_link.'">'.$escaped_link.'</a>';

Y si queremos algo más completo, podemos complicarlo bastante y acceder al protocolo utilizado, puerto, etc (fuente):

function url_origin($s, $use_forwarded_host=false) {

  $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 = ( $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;

Entonces hay quien argumentará que utilizar $_SERVER['HTTP_HOST'] no es un método seguro, ya que es definido en las cabeceras de la solicitud, lo que implica que el cliente (navegador) puede enviar el valor que quiera, y que en su lugar habría que utilizar $_SERVER['SERVER_NAME'], ambos deberían contener el mismo valor pero $_SERVER['SERVER_NAME'] es definido por la configuración del servidor y el cliente no lo puede modificar. Utiliza el que necesites: la cabecera de la solicitud o la configuración del servidor. En el bloque de código anterior se utiliza primero $_SERVER['HTTP_HOST'] y si no está definido se utiliza $_SERVER['SERVER_NAME'] (tenlo en cuenta si lo vas a utilizar).

Pero la mayoría de las veces no hay que complicarse tanto pues se necesita sólo alguna de la información de la superglobal $_SERVER y no la URL solicitada como tal. En el manual PHP sobre $_SERVER puedes ver toda la información disponible en esta variable, o puedes hacer un var_dump( $_SERVER ) para ver la información disponible en tu propia web. Alguna de la más comúnmente utilizada, respecto a la URL, es:

$_SERVER[‘SERVER_NAME’] y $_SERVER[‘HTTP_HOST’]

Ambos contienen el host, lo que generalmente llamamos dominio. La diferencia entre ambos, como se mencionó antes, es que $_SERVER['SERVER_NAME'] toma el valor de la configuración del servidor y $_SERVER['HTTP_HOST'] toma el valor de las cabeceras HTTP de la solicitud realizada por el cliente. En teoría (y en la práctica) es posible que ambos no coincidan.

$_SERVER[‘REQUEST_URI’]

Se puede decir que es todo lo que hay después del dominio, incluyendo el query string. Por ejemplo, en la URL http://midominio.com/una/url/cualquiera?bar=foo el valor de $_SERVER['REQUEST_URI'] sería una/url/cualquiera?bar=foo. Hay que tener en cuenta que los identificadores de fragmento nunca son enviados al servidor, por ejemplo, si se solicita http://midominio.com/una/url#un-identificador, la parte #un-identificador no es enviada al servidor en la solicitud y no estará disponible en $_SERVER['REQUEST_URI']; los identificadores de fragmento si están disponibles en javascript.

$_SERVER[‘QUERY_STRING’]

Contiene la llamada cadena de consulta. Por ejemplo, en http://midominio.com/una/url/cualquiera?bar=foo&bar2=foo2, el query string es ?bar=foo&bar2=foo2, aunque generalmente se utiliza $_GET o $_REQUEST para acceder a las diferentes variables de la cadena de consulta y sus respectivos valores.