Source for file url.php

Documentation is available at url.php

  1. <?php
  2. /**
  3.  *  base include file for SimpleTest
  4.  *  @package    SimpleTest
  5.  *  @subpackage WebTester
  6.  *  @version    $Id: url.php 1723 2008-04-08 00:34:10Z lastcraft $
  7.  */
  8.  
  9. /**#@+
  10.  *  include other SimpleTest class files
  11.  */
  12. require_once(dirname(__FILE__'/encoding.php');
  13. /**#@-*/
  14.  
  15.  *    URL parser to replace parse_url() PHP function which
  16.  *    got broken in PHP 4.3.0. Adds some browser specific
  17.  *    functionality such as expandomatics.
  18.  *    Guesses a bit trying to separate the host from
  19.  *    the path and tries to keep a raw, possibly unparsable,
  20.  *    request string as long as possible.
  21.  *    @package SimpleTest
  22.  *    @subpackage WebTester
  23.  */
  24. class SimpleUrl {
  25.     var $_scheme;
  26.     var $_username;
  27.     var $_password;
  28.     var $_host;
  29.     var $_port;
  30.     var $_path;
  31.     var $_request;
  32.     var $_fragment;
  33.     var $_x;
  34.     var $_y;
  35.     var $_target;
  36.     var $_raw = false;
  37.     
  38.     /**
  39.      *    Constructor. Parses URL into sections.
  40.      *    @param string $url        Incoming URL.
  41.      *    @access public
  42.      */
  43.     function SimpleUrl($url ''{
  44.         list($x$y$this->_chompCoordinates($url);
  45.         $this->setCoordinates($x$y);
  46.         $this->_scheme = $this->_chompScheme($url);
  47.         list($this->_username$this->_password$this->_chompLogin($url);
  48.         $this->_host = $this->_chompHost($url);
  49.         $this->_port = false;
  50.         if (preg_match('/(.*?):(.*)/'$this->_host$host_parts)) {
  51.             $this->_host = $host_parts[1];
  52.             $this->_port = (integer)$host_parts[2];
  53.         }
  54.         $this->_path = $this->_chompPath($url);
  55.         $this->_request = $this->_parseRequest($this->_chompRequest($url));
  56.         $this->_fragment = (strncmp($url"#"1== substr($url1false);
  57.         $this->_target = false;
  58.     }
  59.     
  60.     /**
  61.      *    Extracts the X, Y coordinate pair from an image map.
  62.      *    @param string $url   URL so far. The coordinates will be
  63.      *                          removed.
  64.      *    @return array        X, Y as a pair of integers.
  65.      *    @access private
  66.      */
  67.     function _chompCoordinates(&$url{
  68.         if (preg_match('/(.*)\?(\d+),(\d+)$/'$url$matches)) {
  69.             $url $matches[1];
  70.             return array((integer)$matches[2](integer)$matches[3]);
  71.         }
  72.         return array(falsefalse);
  73.     }
  74.     
  75.     /**
  76.      *    Extracts the scheme part of an incoming URL.
  77.      *    @param string $url   URL so far. The scheme will be
  78.      *                          removed.
  79.      *    @return string       Scheme part or false.
  80.      *    @access private
  81.      */
  82.     function _chompScheme(&$url{
  83.         if (preg_match('/^([^\/:]*):(\/\/)(.*)/'$url$matches)) {
  84.             $url $matches[2$matches[3];
  85.             return $matches[1];
  86.         }
  87.         return false;
  88.     }
  89.     
  90.     /**
  91.      *    Extracts the username and password from the
  92.      *    incoming URL. The // prefix will be reattached
  93.      *    to the URL after the doublet is extracted.
  94.      *    @param string $url    URL so far. The username and
  95.      *                           password are removed.
  96.      *    @return array         Two item list of username and
  97.      *                           password. Will urldecode() them.
  98.      *    @access private
  99.      */
  100.     function _chompLogin(&$url{
  101.         $prefix '';
  102.         if (preg_match('/^(\/\/)(.*)/'$url$matches)) {
  103.             $prefix $matches[1];
  104.             $url $matches[2];
  105.         }
  106.         if (preg_match('/^([^\/]*)@(.*)/'$url$matches)) {
  107.             $url $prefix $matches[2];
  108.             $parts split(":"$matches[1]);
  109.             return array(
  110.                     urldecode($parts[0]),
  111.                     isset($parts[1]urldecode($parts[1]false);
  112.         }
  113.         $url $prefix $url;
  114.         return array(falsefalse);
  115.     }
  116.     
  117.     /**
  118.      *    Extracts the host part of an incoming URL.
  119.      *    Includes the port number part. Will extract
  120.      *    the host if it starts with // or it has
  121.      *    a top level domain or it has at least two
  122.      *    dots.
  123.      *    @param string $url    URL so far. The host will be
  124.      *                           removed.
  125.      *    @return string        Host part guess or false.
  126.      *    @access private
  127.      */
  128.     function _chompHost(&$url{
  129.         if (preg_match('/^(\/\/)(.*?)(\/.*|\?.*|#.*|$)/'$url$matches)) {
  130.             $url $matches[3];
  131.             return $matches[2];
  132.         }
  133.         if (preg_match('/(.*?)(\.\.\/|\.\/|\/|\?|#|$)(.*)/'$url$matches)) {
  134.             $tlds SimpleUrl::getAllTopLevelDomains();
  135.             if (preg_match('/[a-z0-9\-]+\.(' $tlds ')/i'$matches[1])) {
  136.                 $url $matches[2$matches[3];
  137.                 return $matches[1];
  138.             elseif (preg_match('/[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z0-9\-]+/i'$matches[1])) {
  139.                 $url $matches[2$matches[3];
  140.                 return $matches[1];
  141.             }
  142.         }
  143.         return false;
  144.     }
  145.     
  146.     /**
  147.      *    Extracts the path information from the incoming
  148.      *    URL. Strips this path from the URL.
  149.      *    @param string $url     URL so far. The host will be
  150.      *                            removed.
  151.      *    @return string         Path part or '/'.
  152.      *    @access private
  153.      */
  154.     function _chompPath(&$url{
  155.         if (preg_match('/(.*?)(\?|#|$)(.*)/'$url$matches)) {
  156.             $url $matches[2$matches[3];
  157.             return ($matches[1$matches[1'');
  158.         }
  159.         return '';
  160.     }
  161.     
  162.     /**
  163.      *    Strips off the request data.
  164.      *    @param string $url  URL so far. The request will be
  165.      *                         removed.
  166.      *    @return string      Raw request part.
  167.      *    @access private
  168.      */
  169.     function _chompRequest(&$url{
  170.         if (preg_match('/\?(.*?)(#|$)(.*)/'$url$matches)) {
  171.             $url $matches[2$matches[3];
  172.             return $matches[1];
  173.         }
  174.         return '';
  175.     }
  176.         
  177.     /**
  178.      *    Breaks the request down into an object.
  179.      *    @param string $raw           Raw request.
  180.      *    @return SimpleFormEncoding    Parsed data.
  181.      *    @access private
  182.      */
  183.     function _parseRequest($raw{
  184.         $this->_raw = $raw;
  185.         $request new SimpleGetEncoding();
  186.         foreach (split("&"$rawas $pair{
  187.             if (preg_match('/(.*?)=(.*)/'$pair$matches)) {
  188.                 $request->add($matches[1]urldecode($matches[2]));
  189.             elseif ($pair{
  190.                 $request->add($pair'');
  191.             }
  192.         }
  193.         return $request;
  194.     }
  195.     
  196.     /**
  197.      *    Accessor for protocol part.
  198.      *    @param string $default    Value to use if not present.
  199.      *    @return string            Scheme name, e.g "http".
  200.      *    @access public
  201.      */
  202.     function getScheme($default false{
  203.         return $this->_scheme ? $this->_scheme : $default;
  204.     }
  205.     
  206.     /**
  207.      *    Accessor for user name.
  208.      *    @return string    Username preceding host.
  209.      *    @access public
  210.      */
  211.     function getUsername({
  212.         return $this->_username;
  213.     }
  214.     
  215.     /**
  216.      *    Accessor for password.
  217.      *    @return string    Password preceding host.
  218.      *    @access public
  219.      */
  220.     function getPassword({
  221.         return $this->_password;
  222.     }
  223.     
  224.     /**
  225.      *    Accessor for hostname and port.
  226.      *    @param string $default    Value to use if not present.
  227.      *    @return string            Hostname only.
  228.      *    @access public
  229.      */
  230.     function getHost($default false{
  231.         return $this->_host ? $this->_host : $default;
  232.     }
  233.     
  234.     /**
  235.      *    Accessor for top level domain.
  236.      *    @return string       Last part of host.
  237.      *    @access public
  238.      */
  239.     function getTld({
  240.         $path_parts pathinfo($this->getHost());
  241.         return (isset($path_parts['extension']$path_parts['extension'false);
  242.     }
  243.     
  244.     /**
  245.      *    Accessor for port number.
  246.      *    @return integer    TCP/IP port number.
  247.      *    @access public
  248.      */
  249.     function getPort({
  250.         return $this->_port;
  251.     }        
  252.             
  253.     /**
  254.      *    Accessor for path.
  255.      *    @return string    Full path including leading slash if implied.
  256.      *    @access public
  257.      */
  258.     function getPath({
  259.         if ($this->_path && $this->_host{
  260.             return '/';
  261.         }
  262.         return $this->_path;
  263.     }
  264.     
  265.     /**
  266.      *    Accessor for page if any. This may be a
  267.      *    directory name if ambiguious.
  268.      *    @return            Page name.
  269.      *    @access public
  270.      */
  271.     function getPage({
  272.         if (preg_match('/([^\/]*?)$/'$this->getPath()$matches)) {
  273.             return false;
  274.         }
  275.         return $matches[1];
  276.     }
  277.     
  278.     /**
  279.      *    Gets the path to the page.
  280.      *    @return string       Path less the page.
  281.      *    @access public
  282.      */
  283.     function getBasePath({
  284.         if (preg_match('/(.*\/)[^\/]*?$/'$this->getPath()$matches)) {
  285.             return false;
  286.         }
  287.         return $matches[1];
  288.     }
  289.     
  290.     /**
  291.      *    Accessor for fragment at end of URL after the "#".
  292.      *    @return string    Part after "#".
  293.      *    @access public
  294.      */
  295.     function getFragment({
  296.         return $this->_fragment;
  297.     }
  298.     
  299.     /**
  300.      *    Sets image coordinates. Set to false to clear
  301.      *    them.
  302.      *    @param integer $x    Horizontal position.
  303.      *    @param integer $y    Vertical position.
  304.      *    @access public
  305.      */
  306.     function setCoordinates($x false$y false{
  307.         if (($x === false|| ($y === false)) {
  308.             $this->_x = $this->_y = false;
  309.             return;
  310.         }
  311.         $this->_x = (integer)$x;
  312.         $this->_y = (integer)$y;
  313.     }
  314.     
  315.     /**
  316.      *    Accessor for horizontal image coordinate.
  317.      *    @return integer        X value.
  318.      *    @access public
  319.      */
  320.     function getX({
  321.         return $this->_x;
  322.     }
  323.         
  324.     /**
  325.      *    Accessor for vertical image coordinate.
  326.      *    @return integer        Y value.
  327.      *    @access public
  328.      */
  329.     function getY({
  330.         return $this->_y;
  331.     }
  332.     
  333.     /**
  334.      *    Accessor for current request parameters
  335.      *    in URL string form. Will return teh original request
  336.      *    if at all possible even if it doesn't make much
  337.      *    sense.
  338.      *    @return string   Form is string "?a=1&b=2", etc.
  339.      *    @access public
  340.      */
  341.     function getEncodedRequest({
  342.         if ($this->_raw{
  343.             $encoded $this->_raw;
  344.         else {
  345.             $encoded $this->_request->asUrlRequest();
  346.         }
  347.         if ($encoded{
  348.             return '?' preg_replace('/^\?/'''$encoded);
  349.         }
  350.         return '';
  351.     }
  352.     
  353.     /**
  354.      *    Adds an additional parameter to the request.
  355.      *    @param string $key            Name of parameter.
  356.      *    @param string $value          Value as string.
  357.      *    @access public
  358.      */
  359.     function addRequestParameter($key$value{
  360.         $this->_raw = false;
  361.         $this->_request->add($key$value);
  362.     }
  363.     
  364.     /**
  365.      *    Adds additional parameters to the request.
  366.      *    @param hash/SimpleFormEncoding $parameters   Additional
  367.      *                                                 parameters.
  368.      *    @access public
  369.      */
  370.     function addRequestParameters($parameters{
  371.         $this->_raw = false;
  372.         $this->_request->merge($parameters);
  373.     }
  374.     
  375.     /**
  376.      *    Clears down all parameters.
  377.      *    @access public
  378.      */
  379.     function clearRequest({
  380.         $this->_raw = false;
  381.         $this->_request = &new SimpleGetEncoding();
  382.     }
  383.     
  384.     /**
  385.      *    Gets the frame target if present. Although
  386.      *    not strictly part of the URL specification it
  387.      *    acts as similarily to the browser.
  388.      *    @return boolean/string    Frame name or false if none.
  389.      *    @access public
  390.      */
  391.     function getTarget({
  392.         return $this->_target;
  393.     }
  394.     
  395.     /**
  396.      *    Attaches a frame target.
  397.      *    @param string $frame        Name of frame.
  398.      *    @access public
  399.      */
  400.     function setTarget($frame{
  401.         $this->_raw = false;
  402.         $this->_target = $frame;
  403.     }
  404.     
  405.     /**
  406.      *    Renders the URL back into a string.
  407.      *    @return string        URL in canonical form.
  408.      *    @access public
  409.      */
  410.     function asString({
  411.         $path $this->_path;
  412.         $scheme $identity $host $encoded $fragment '';
  413.         if ($this->_username && $this->_password{
  414.             $identity $this->_username . ':' $this->_password . '@';
  415.         }
  416.         if ($this->getHost()) {
  417.             $scheme $this->getScheme($this->getScheme('http';
  418.             $scheme .= "://";
  419.             $host $this->getHost();
  420.         }
  421.         if (substr($this->_path01== '/'{
  422.             $path $this->normalisePath($this->_path);
  423.         }
  424.         $encoded $this->getEncodedRequest();
  425.         $fragment $this->getFragment('#'$this->getFragment('';
  426.         $coords $this->getX(=== false '' '?' $this->getX(',' $this->getY();
  427.         return "$scheme$identity$host$path$encoded$fragment$coords";
  428.     }
  429.     
  430.     /**
  431.      *    Replaces unknown sections to turn a relative
  432.      *    URL into an absolute one. The base URL can
  433.      *    be either a string or a SimpleUrl object.
  434.      *    @param string/SimpleUrl $base       Base URL.
  435.      *    @access public
  436.      */
  437.     function makeAbsolute($base{
  438.         if (is_object($base)) {
  439.             $base new SimpleUrl($base);
  440.         }
  441.         if ($this->getHost()) {
  442.             $scheme $this->getScheme();
  443.             $host $this->getHost();
  444.             $port $this->getPort(':' $this->getPort('';
  445.             $identity $this->getIdentity($this->getIdentity('@' '';
  446.             if ($identity{
  447.                 $identity $base->getIdentity($base->getIdentity('@' '';
  448.             }
  449.         else {
  450.             $scheme $base->getScheme();
  451.             $host $base->getHost();
  452.             $port $base->getPort(':' $base->getPort('';
  453.             $identity $base->getIdentity($base->getIdentity('@' '';
  454.         }
  455.         $path $this->normalisePath($this->_extractAbsolutePath($base));
  456.         $encoded $this->getEncodedRequest();
  457.         $fragment $this->getFragment('#'$this->getFragment('';
  458.         $coords $this->getX(=== false '' '?' $this->getX(',' $this->getY();
  459.         return new SimpleUrl("$scheme://$identity$host$port$path$encoded$fragment$coords");
  460.     }
  461.     
  462.     /**
  463.      *    Replaces unknown sections of the path with base parts
  464.      *    to return a complete absolute one.
  465.      *    @param string/SimpleUrl $base       Base URL.
  466.      *    @param string                       Absolute path.
  467.      *    @access private
  468.      */
  469.     function _extractAbsolutePath($base{
  470.         if ($this->getHost()) {
  471.             return $this->_path;
  472.         }
  473.         if ($this->_isRelativePath($this->_path)) {
  474.             return $this->_path;
  475.         }
  476.         if ($this->_path{
  477.             return $base->getBasePath($this->_path;
  478.         }
  479.         return $base->getPath();
  480.     }
  481.     
  482.     /**
  483.      *    Simple test to see if a path part is relative.
  484.      *    @param string $path        Path to test.
  485.      *    @return boolean            True if starts with a "/".
  486.      *    @access private
  487.      */
  488.     function _isRelativePath($path{
  489.         return (substr($path01!= '/');
  490.     }
  491.     
  492.     /**
  493.      *    Extracts the username and password for use in rendering
  494.      *    a URL.
  495.      *    @return string/boolean    Form of username:password or false.
  496.      *    @access public
  497.      */
  498.     function getIdentity({
  499.         if ($this->_username && $this->_password{
  500.             return $this->_username . ':' $this->_password;
  501.         }
  502.         return false;
  503.     }
  504.     
  505.     /**
  506.      *    Replaces . and .. sections of the path.
  507.      *    @param string $path    Unoptimised path.
  508.      *    @return string         Path with dots removed if possible.
  509.      *    @access public
  510.      */
  511.     function normalisePath($path{
  512.         $path preg_replace('|/\./|''/'$path);
  513.         return preg_replace('|/[^/]+/\.\./|''/'$path);
  514.     }
  515.     
  516.     /**
  517.      *    A pipe seperated list of all TLDs that result in two part
  518.      *    domain names.
  519.      *    @return string        Pipe separated list.
  520.      *    @access public
  521.      *    @static
  522.      */
  523.     function getAllTopLevelDomains({
  524.         return 'com|edu|net|org|gov|mil|int|biz|info|name|pro|aero|coop|museum';
  525.     }
  526. }
  527. ?>

Documentation generated on Sun, 04 May 2008 09:22:23 -0500 by phpDocumentor 1.3.0