An update to the function by FredLudd at gmail dot com.  I added IPv6 functionality as well.
<?php
function j_parseUrl($url) {
  $r  = "(?:([a-z0-9+-._]+)://)?";
  $r .= "(?:";
  $r .=   "(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9a-f]{2})*)@)?";
  $r .=   "(?:\[((?:[a-z0-9:])*)\])?";
  $r .=   "((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9a-f]{2})*)";
  $r .=   "(?::(\d*))?";
  $r .=   "(/(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9a-f]{2})*)?";
  $r .=   "|";
  $r .=   "(/?";
  $r .=     "(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+";
  $r .=     "(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9a-f]{2})*";
  $r .=    ")?";
  $r .= ")";
  $r .= "(?:\?((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9a-f]{2})*))?";
  $r .= "(?:#((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9a-f]{2})*))?";
  preg_match("`$r`i", $url, $match);
  $parts = array(
            "scheme"=>'',
            "userinfo"=>'',
            "authority"=>'',
            "host"=> '',
            "port"=>'',
            "path"=>'',
            "query"=>'',
            "fragment"=>'');
  switch (count ($match)) {
    case 10: $parts['fragment'] = $match[9];
    case 9: $parts['query'] = $match[8];
    case 8: $parts['path'] =  $match[7];
    case 7: $parts['path'] =  $match[6] . $parts['path'];
    case 6: $parts['port'] =  $match[5];
    case 5: $parts['host'] =  $match[3]?"[".$match[3]."]":$match[4];
    case 4: $parts['userinfo'] =  $match[2];
    case 3: $parts['scheme'] =  $match[1];
  }
  $parts['authority'] = ($parts['userinfo']?$parts['userinfo']."@":"").
                         $parts['host'].
                        ($parts['port']?":".$parts['port']:"");
  return $parts;
}
?>
When using the url
  /* line too long for this site's comment handler */
  "foo://username:password@[2001:4860:0:2001::68]:8042".
      "/over/there/index.dtb;type=animal?name=ferret#nose"
The original would return
Array
(
    [scheme] => foo
    [userinfo] => username:password
    [authority] => username:password@
    [host] => 
    [port] => 
    [path] => 
    [query] => 
    [fragment] => 
)
The new one returns
Array
(
    [scheme] => foo
    [userinfo] => username:password
    [authority] => username:password@[2001:4860:0:2001::68]:8042
    [host] => [2001:4860:0:2001::68]
    [port] => 8042
    [path] => /over/there/index.dtb;type=animal
    [query] => name=ferret
    [fragment] => nose
)
All of the other examples FredLudd used below still work exactly the same.