HTTP_Client
[ class tree: HTTP_Client ] [ index: HTTP_Client ] [ all elements ]

Source for file Client.php

Documentation is available at Client.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * A simple HTTP client class.
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE:
  10.  * 
  11.  * Copyright (c) 2003-2008, Alexey Borzov <avb@php.net>
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  *
  18.  *    * Redistributions of source code must retain the above copyright
  19.  *      notice, this list of conditions and the following disclaimer.
  20.  *    * Redistributions in binary form must reproduce the above copyright
  21.  *      notice, this list of conditions and the following disclaimer in the
  22.  *      documentation and/or other materials provided with the distribution.
  23.  *    * The name of the author may not be used to endorse or promote products
  24.  *      derived from this software without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  30.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  34.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37.  *
  38.  * @category    HTTP
  39.  * @package     HTTP_Client
  40.  * @author      Alexey Borzov <avb@php.net>
  41.  * @license     http://opensource.org/licenses/bsd-license.php New BSD License
  42.  * @version     CVS: $Id: Client.php,v 1.11 2008/10/11 14:29:27 avb Exp $
  43.  * @link        http://pear.php.net/package/HTTP_Client
  44.  */
  45.  
  46. /*
  47.  * Do this define in your script if you wish HTTP_Client to follow browser 
  48.  * quirks rather than HTTP specification (RFC2616). This means:
  49.  *   - do a GET request after redirect with code 301, rather than use the
  50.  *     same method as before redirect.
  51.  */
  52. // define('HTTP_CLIENT_QUIRK_MODE', true);
  53.  
  54. /**
  55.  * Class for performing HTTP requests
  56.  */
  57. require_once 'HTTP/Request.php';
  58. /**
  59.  * Class used to store cookies and pass them between HTTP requests.
  60.  */
  61. require_once 'HTTP/Client/CookieManager.php';
  62.  
  63. /**
  64.  * A simple HTTP client class.
  65.  * 
  66.  * The class wraps around HTTP_Request providing a higher-level
  67.  * API for performing multiple HTTP requests
  68.  *
  69.  * Note that the class implements all the methods defined by the Iterator
  70.  * interface for going over the received responses. Being PHP4-compatible it is
  71.  * not declared with 'implements Iterator', though. Therefore if you are
  72.  * running PHP5 and want to use HTTP_Client in 'foreach' context you should do
  73.  * the following:
  74.  * <code>
  75.  * class PHP5_HTTP_Client extends HTTP_Client implements Iterator {}
  76.  * 
  77.  * $client = new PHP5_HTTP_Client();
  78.  * 
  79.  * // ... perform requests ...
  80.  * 
  81.  * foreach ($client as $url => $response) {
  82.  *     // do something
  83.  * }
  84.  * </code>
  85.  *
  86.  * If you are running PHP4 you'll have to call the methods manually:
  87.  * <code>
  88.  * for ($client->rewind(); $client->valid(); $client->next()) {
  89.  *     $url = $client->key();
  90.  *     $response = $client->current();
  91.  *     // do something
  92.  * }
  93.  * </code>
  94.  * 
  95.  * @category    HTTP
  96.  * @package     HTTP_Client
  97.  * @author      Alexey Borzov <avb@php.net>
  98.  * @version     Release: 1.2.1
  99.  */
  100. {
  101.    /**#@+
  102.     * @access private
  103.     */
  104.    /**
  105.     * Cookie manager object
  106.     * @var HTTP_Client_CookieManager 
  107.     */
  108.     var $_cookieManager;
  109.  
  110.    /**
  111.     * Received HTTP responses
  112.     * @var array 
  113.     */
  114.     var $_responses;
  115.  
  116.    /**
  117.     * Default headers to send on every request
  118.     * @var array 
  119.     */
  120.     var $_defaultHeaders = array();
  121.  
  122.    /**
  123.     * Default parameters for HTTP_Request's constructor
  124.     * @var array 
  125.     */
  126.     var $_defaultRequestParams = array();
  127.  
  128.    /**
  129.     * How many redirects were done
  130.     * @var integer 
  131.     */
  132.     var $_redirectCount = 0;
  133.  
  134.    /**
  135.     * Maximum allowed redirects
  136.     * @var integer 
  137.     */
  138.     var $_maxRedirects = 5;
  139.  
  140.    /**
  141.     * Listeners attached to the client
  142.     * @var array 
  143.     */
  144.     var $_listeners = array();
  145.  
  146.    /**
  147.     * Whether the listener should be propagated to Request objects
  148.     * @var array 
  149.     */
  150.     var $_propagate = array();
  151.  
  152.    /**
  153.     * Whether to keep all the responses or just the most recent one
  154.     * @var boolean 
  155.     */
  156.     var $_isHistoryEnabled = true;
  157.  
  158.    /**
  159.     * Index for iteration over the responses
  160.     * @var integer 
  161.     */
  162.     var $_idx = 0;
  163.    /**#@-*/
  164.  
  165.    /**
  166.     * Constructor
  167.     * 
  168.     * @access   public
  169.     * @param    array                       Parameters to pass to HTTP_Request's constructor
  170.     * @param    array                       Default headers to send on every request
  171.     * @param    HTTP_Client_CookieManager   Cookie manager object to use
  172.     */
  173.     function HTTP_Client($defaultRequestParams = null$defaultHeaders = null$cookieManager = null)
  174.     {
  175.         if (!empty($cookieManager&& is_a($cookieManager'HTTP_Client_CookieManager')) {
  176.             $this->_cookieManager $cookieManager;
  177.         else {
  178.             $this->_cookieManager =new HTTP_Client_CookieManager();
  179.         }
  180.         if (isset($defaultHeaders)) {
  181.             $this->setDefaultHeader($defaultHeaders);
  182.         }
  183.         if (isset($defaultRequestParams)) {
  184.             $this->setRequestParameter($defaultRequestParams);
  185.         }
  186.     }
  187.  
  188.  
  189.    /**
  190.     * Sets the maximum redirects that will be processed.
  191.     * 
  192.     * Setting this to 0 disables redirect processing. If not 0 and the
  193.     * number of redirects in a request is bigger than this number, then an
  194.     * error will be raised.
  195.     * 
  196.     * @access   public
  197.     * @param    int     Max number of redirects to process
  198.     */
  199.     function setMaxRedirects($value)
  200.     {
  201.         $this->_maxRedirects $value;
  202.     }
  203.  
  204.  
  205.    /**
  206.     * Sets whether to keep all the responses or just the most recent one
  207.     *
  208.     * @access public
  209.     * @param  bool      Whether to enable history
  210.     */
  211.     function enableHistory($enable)
  212.     {
  213.         $this->_isHistoryEnabled = (bool)$enable;
  214.     }
  215.  
  216.    /**
  217.     * Creates a HTTP_Request objects, applying all the necessary defaults
  218.     *
  219.     * @param    string   URL
  220.     * @param    string   Method, constants are defined in HTTP_Request
  221.     * @param    array    Extra headers to send
  222.     * @access   private
  223.     * @return   HTTP_Request    Request object with all defaults applied
  224.     */
  225.     function &_createRequest($url$method = HTTP_REQUEST_METHOD_GET$headers = array())
  226.     {
  227.         $req =new HTTP_Request($url$this->_defaultRequestParams);
  228.         $req->setMethod($method);
  229.         foreach ($this->_defaultHeaders as $name => $value{
  230.             $req->addHeader($name$value);
  231.         }
  232.         foreach ($headers as $name => $value{
  233.             $req->addHeader($name$value);
  234.         }
  235.         $this->_cookieManager->passCookies($req);
  236.         foreach ($this->_propagate as $id => $propagate{
  237.             if ($propagate{
  238.                 $req->attach($this->_listeners[$id]);
  239.             }
  240.         }
  241.         return $req;
  242.     }
  243.     
  244.  
  245.    /**
  246.     * Sends a 'HEAD' HTTP request
  247.     *
  248.     * @param    string  URL
  249.     * @param    array   Extra headers to send
  250.     * @access   public
  251.     * @return   integer HTTP response code
  252.     * @throws   PEAR_Error
  253.     */
  254.     function head($url$headers = array())
  255.     {
  256.         $request =$this->_createRequest($urlHTTP_REQUEST_METHOD_HEAD$headers);
  257.         return $this->_performRequest($request);
  258.     }
  259.    
  260.  
  261.    /**
  262.     * Sends a 'GET' HTTP request
  263.     * 
  264.     * @param    string  URL
  265.     * @param    mixed   additional data to send
  266.     * @param    boolean Whether the data is already urlencoded
  267.     * @param    array   Extra headers to send
  268.     * @access   public
  269.     * @return   integer HTTP response code
  270.     * @throws   PEAR_Error
  271.     */
  272.     function get($url$data = null$preEncoded = false$headers = array())
  273.     {
  274.         $request =$this->_createRequest($urlHTTP_REQUEST_METHOD_GET$headers);
  275.         if (is_array($data)) {
  276.             foreach ($data as $name => $value{
  277.                 $request->addQueryString($name$value$preEncoded);
  278.             }
  279.         elseif (isset($data)) {
  280.             $request->addRawQueryString($data$preEncoded);
  281.         }
  282.         return $this->_performRequest($request);
  283.     }
  284.  
  285.  
  286.    /**
  287.     * Sends a 'POST' HTTP request
  288.     *
  289.     * @param    string  URL
  290.     * @param    mixed   Data to send
  291.     * @param    boolean Whether the data is already urlencoded
  292.     * @param    array   Files to upload. Elements of the array should have the form:
  293.     *                    array(name, filename(s)[, content type]), see HTTP_Request::addFile()
  294.     * @param    array   Extra headers to send
  295.     * @access   public
  296.     * @return   integer HTTP response code
  297.     * @throws   PEAR_Error
  298.     */
  299.     function post($url$data$preEncoded = false$files = array()$headers = array())
  300.     {
  301.         $request =$this->_createRequest($urlHTTP_REQUEST_METHOD_POST$headers);
  302.         if (is_array($data)) {
  303.             foreach ($data as $name => $value{
  304.                 $request->addPostData($name$value$preEncoded);
  305.             }
  306.         else {
  307.             $request->addRawPostData($data$preEncoded);
  308.         }
  309.         foreach ($files as $fileData{
  310.             $res call_user_func_array(array(&$request'addFile')$fileData);
  311.             if (PEAR::isError($res)) {
  312.                 return $res;
  313.             }
  314.         }
  315.         return $this->_performRequest($request);
  316.     }
  317.  
  318.  
  319.    /**
  320.     * Sends a 'PUT' HTTP request
  321.     *
  322.     * @param    string  URL
  323.     * @param    string  Request body
  324.     * @param    array   Extra headers to send
  325.     * @access   public
  326.     * @return   integer HTTP response code
  327.     * @throws   PEAR_Error
  328.     */
  329.     function put($url$body ''$headers = array())
  330.     {
  331.         $request =$this->_createRequest($urlHTTP_REQUEST_METHOD_PUT$headers);
  332.         $request->setBody($body);
  333.         return $this->_performRequest($request);
  334.     }
  335.  
  336.  
  337.    /**
  338.     * Sends a 'DELETE' HTTP request
  339.     *
  340.     * @param    string  URL
  341.     * @param    array   Extra headers to send
  342.     * @access   public
  343.     * @return   integer HTTP response code
  344.     * @throws   PEAR_Error
  345.     */
  346.     function delete($url$headers = array())
  347.     {
  348.         $request =$this->_createRequest($urlHTTP_REQUEST_METHOD_DELETE$headers);
  349.         return $this->_performRequest($request);
  350.     
  351.  
  352.    /**
  353.     * Sets default header(s) for HTTP requests
  354.     *
  355.     * @param    mixed   header name or array ('header name' => 'header value')
  356.     * @param    string  header value if $name is not an array
  357.     * @access   public
  358.     */
  359.     function setDefaultHeader($name$value = null)
  360.     {
  361.         if (is_array($name)) {
  362.             $this->_defaultHeaders array_merge($this->_defaultHeaders$name);
  363.         else {
  364.             $this->_defaultHeaders[$name$value;
  365.         }
  366.     }
  367.  
  368.  
  369.    /**
  370.     * Sets parameter(s) for HTTP requests
  371.     *
  372.     * @param    mixed   parameter name or array ('parameter name' => 'parameter value')
  373.     * @param    string  parameter value if $name is not an array
  374.     * @access   public
  375.     */
  376.     function setRequestParameter($name$value = null)
  377.     {
  378.         if (is_array($name)) {
  379.             $this->_defaultRequestParams array_merge($this->_defaultRequestParams$name);
  380.         else {
  381.             $this->_defaultRequestParams[$name$value;
  382.         }
  383.     }
  384.       
  385.  
  386.    /**
  387.     * Performs a request, processes redirects
  388.     *
  389.     * @param    HTTP_Request    Request object
  390.     * @access   private
  391.     * @return   integer         HTTP response code
  392.     * @throws   PEAR_Error
  393.     */
  394.     function _performRequest(&$request)
  395.     {
  396.         // If this is not a redirect, notify the listeners of new request
  397.         if (0 == $this->_redirectCount && '' != $request->getUrl()) {
  398.             $this->_notify('request'$request->getUrl());
  399.         }
  400.         if (PEAR::isError($err $request->sendRequest())) {
  401.             $this->_redirectCount = 0;
  402.             return $err;
  403.         }
  404.         $this->_pushResponse($request);
  405.  
  406.         $code $request->getResponseCode();
  407.         if ($this->_maxRedirects > 0{
  408.             if (in_array($codearray(300301302303307))) {
  409.                 if ('' == ($location $request->getResponseHeader('Location'))) {
  410.                     $this->_redirectCount = 0;
  411.                     return PEAR::raiseError("No 'Location' field on redirect");
  412.                 }
  413.                 // Bug #5759: do not try to follow non-HTTP redirects
  414.                 if (null === ($redirectUrl $this->_redirectUrl($request->_url$location))) {
  415.                     $this->_redirectCount = 0;
  416.                     return $code;
  417.                 }
  418.             // Redirect via <meta http-equiv="Refresh"> tag, see request #5734
  419.             elseif (200 <= $code && $code < 300{
  420.                 $redirectUrl $this->_getMetaRedirect($request);
  421.             }
  422.         }
  423.         if (!empty($redirectUrl)) {
  424.             if (++$this->_redirectCount $this->_maxRedirects{
  425.                 $this->_redirectCount = 0;
  426.                 return PEAR::raiseError('Too many redirects');
  427.             }
  428.             // Notify of redirection
  429.             $this->_notify('httpRedirect'$redirectUrl);
  430.             // we access the private properties directly, as there are no accessors for them
  431.             switch ($request->_method{
  432.                 case HTTP_REQUEST_METHOD_POST:
  433.                     // Bug #13487: if doing a redirect via <meta>, use GET 
  434.                     if (302 == $code || 303 == $code || $code < 300 ||
  435.                         (301 == $code && defined('HTTP_CLIENT_QUIRK_MODE'))) 
  436.                     {
  437.                         return $this->get($redirectUrl);
  438.                     elseif (!empty($request->_postData|| !empty($request->_postFiles)) {
  439.                         $postFiles = array();
  440.                         foreach ($request->_postFiles as $name => $data{
  441.                             $postFiles[= array($name$data['name']$data['type']);
  442.                         }
  443.                         return $this->post($redirectUrl$request->_postDatatrue$postFiles);
  444.                     else {
  445.                         return $this->post($redirectUrl$request->_bodytrue);
  446.                     }
  447.                 case HTTP_REQUEST_METHOD_HEAD:
  448.                     return (303 == $code$this->get($redirectUrl)$this->head($redirectUrl));
  449.                 case HTTP_REQUEST_METHOD_GET: 
  450.                 default:
  451.                     return $this->get($redirectUrl);
  452.             // switch
  453.  
  454.         else {
  455.             $this->_redirectCount = 0;
  456.             if (400 >= $code{
  457.                 $this->_notify('httpSuccess');
  458.                 $this->setDefaultHeader('Referer'$request->getUrl());
  459.                 // some result processing should go here
  460.             else {
  461.                 $this->_notify('httpError');
  462.             }
  463.         }
  464.         return $code;
  465.     }
  466.  
  467.  
  468.    /**
  469.     * Returns the most recent HTTP response
  470.     *
  471.     * To access previous responses use iteration methods
  472.     * 
  473.     * @access public
  474.     * @return array 
  475.     */
  476.     function &currentResponse()
  477.     {
  478.         return $this->_responses[count($this->_responses- 1];
  479.     }
  480.  
  481.  
  482.    /**
  483.     * Saves the server's response to responses list
  484.     *
  485.     * @param    HTTP_Request    Request object already containing the response
  486.     * @access   private
  487.     */
  488.     function _pushResponse(&$request)
  489.     {
  490.         $this->_cookieManager->updateCookies($request);
  491.         $idx   $this->_isHistoryEnabledcount($this->_responses): 0;
  492.         $this->_responses[$idx= array(
  493.             'url'     => $request->getUrl(),
  494.             'code'    => $request->getResponseCode(),
  495.             'headers' => $request->getResponseHeader(),
  496.             'body'    => $request->getResponseBody()
  497.         );
  498.     }
  499.  
  500.  
  501.    /**
  502.     * Clears object's internal properties
  503.     *
  504.     * @access public
  505.     */
  506.     function reset()
  507.     {
  508.         $this->_cookieManager->reset();
  509.         $this->_responses            = array();
  510.         $this->_defaultHeaders       = array();
  511.         $this->_defaultRequestParams = array();
  512.         $this->_idx                  = 0;
  513.     }
  514.  
  515.  
  516.    /**
  517.     * Adds a Listener to the list of listeners that are notified of
  518.     * the object's events
  519.     *
  520.     * Events sent by HTTP_Client objects:
  521.     * - 'request': sent on HTTP request that is not a redirect
  522.     * - 'httpSuccess': sent when we receive a successfull 2xx response
  523.     * - 'httpRedirect': sent when we receive a redirection response
  524.     * - 'httpError': sent on 4xx, 5xx response
  525.     *
  526.     * @param    HTTP_Request_Listener   Listener to attach
  527.     * @param    boolean                 Whether the listener should be attached
  528.     *                                    to the created HTTP_Request objects
  529.     * @return   boolean                 whether the listener was successfully attached
  530.     * @access   public
  531.     */
  532.     function attach(&$listener$propagate = false)
  533.     {
  534.         if (!is_a($listener'HTTP_Request_Listener')) {
  535.             return false;
  536.         }
  537.         $this->_listeners[$listener->getId()=$listener;
  538.         $this->_propagate[$listener->getId()=  $propagate;
  539.         return true;
  540.     }
  541.  
  542.  
  543.    /**
  544.     * Removes a Listener from the list of listeners
  545.     * 
  546.     * @param    HTTP_Request_Listener   Listener to detach
  547.     * @return   boolean                 Whether the listener was successfully detached
  548.     * @access   public
  549.     */
  550.     function detach(&$listener)
  551.     {
  552.         if (!is_a($listener'HTTP_Request_Listener'|| 
  553.             !isset($this->_listeners[$listener->getId()])) {
  554.             return false;
  555.         }
  556.         unset($this->_listeners[$listener->getId()]$this->_propagate[$listener->getId()]);
  557.         return true;
  558.     }
  559.  
  560.  
  561.    /**
  562.     * Notifies all registered listeners of an event.
  563.     * 
  564.     * @param    string  Event name
  565.     * @param    mixed   Additional data
  566.     * @access   private
  567.     */
  568.     function _notify($event$data = null)
  569.     {
  570.         foreach (array_keys($this->_listenersas $id{
  571.             $this->_listeners[$id]->update($this$event$data);
  572.         }
  573.     }
  574.  
  575.  
  576.    /**
  577.     * Calculates the absolute URL of a redirect
  578.     *  
  579.     * @param    Net_Url     Object containing the request URL
  580.     * @param    string      Value of the 'Location' response header
  581.     * @return   string|nullAbsolute URL we are being redirected to, null in case of non-HTTP URL
  582.     * @access   private
  583.     */
  584.     function _redirectUrl($url$location)
  585.     {
  586.         // If it begins with a scheme (as defined in RFC 2396) then it is absolute URI 
  587.         if (preg_match('/^([a-zA-Z][a-zA-Z0-9+.-]*):/'$location$matches)) {
  588.             // Bug #5759: we shouldn't try to follow non-HTTP redirects
  589.             if ('http' == strtolower($matches[1]|| 'https' == strtolower($matches[1])) {
  590.                 return $location;
  591.             else {
  592.                 return null;
  593.             }
  594.         else {
  595.             if ('/' == $location[0]{
  596.                 $url->path = Net_URL::resolvePath($location);
  597.             elseif('/' == substr($url->path-1)) {
  598.                 $url->path = Net_URL::resolvePath($url->path . $location);
  599.             else {
  600.                 $dirname (DIRECTORY_SEPARATOR == dirname($url->path)'/'dirname($url->path));
  601.                 $url->path = Net_URL::resolvePath($dirname '/' $location);
  602.             }
  603.             $url->querystring = array();
  604.             $url->anchor      = '';
  605.             return $url->getUrl();
  606.         }
  607.     }
  608.  
  609.  
  610.    /**
  611.     * Returns the cookie manager object (e.g. for storing it somewhere)
  612.     *
  613.     * @return HTTP_Client_CookieManager 
  614.     * @access public
  615.     */
  616.     function getCookieManager()
  617.     {
  618.         return $this->_cookieManager;
  619.     }
  620.  
  621.  
  622.    /**
  623.     * Tries to extract a redirect URL from <<meta http-equiv=Refresh>> tag (request #5734)
  624.     *
  625.     * @param    HTTP_Request    A request object already containing the response
  626.     * @return   string|null    Absolute URI we are being redirected to, null if no redirect / invalid redirect
  627.     * @access   private
  628.     */
  629.     function _getMetaRedirect(&$request)
  630.     {
  631.         // Non-HTML response or empty response body
  632.         if ('text/html' != substr($request->getResponseHeader('content-type')09||
  633.             '' == ($body $request->getResponseBody())) {
  634.             return null;
  635.         }
  636.         // No <meta http-equiv=Refresh> tag
  637.         if (!preg_match('!<meta\\s+([^>]*http-equiv\\s*=\\s*("Refresh"|\'Refresh\'|Refresh)[^>]*)>!is'$body$matches)) {
  638.             return null;
  639.         }
  640.         // Just a refresh, no redirect
  641.         if (!preg_match('!content\\s*=\\s*("[^"]+"|\'[^\']+\'|\\S+)!is'$matches[1]$urlMatches)) {
  642.             return null;
  643.         }
  644.         $parts explode(';'('\'' == substr($urlMatches[1]01|| '"' == substr($urlMatches[1]01))
  645.                                substr($urlMatches[1]1-1)$urlMatches[1]);
  646.         if (empty($parts[1]|| !preg_match('/url\\s*=\\s*("[^"]+"|\'[^\']+\'|\\S+)/is'$parts[1]$urlMatches)) {
  647.              return null;
  648.         }
  649.         $url ('\'' == substr($urlMatches[1]01|| '"' == substr($urlMatches[1]01))?
  650.                substr($urlMatches[1]1-1)$urlMatches[1];
  651.         // We do finally have an url... Now check that it's:
  652.         // a) HTTP, b) not to the same page
  653.         $previousUrl $request->getUrl();
  654.         $redirectUrl $this->_redirectUrl($request->_urlhtml_entity_decode($url));
  655.         return (null === $redirectUrl || $redirectUrl == $previousUrl)? null: $redirectUrl
  656.     }
  657.  
  658.  
  659.    /**
  660.     * Returns the current element (HTTP response)
  661.     *
  662.     * @access   public
  663.     * @return   array 
  664.     */ 
  665.     function current()
  666.     {
  667.         $response $this->_responses[$this->_idx];
  668.         unset($response['url']);
  669.         return $response;
  670.     }
  671.  
  672.  
  673.    /**
  674.     * Returns the key of the current element
  675.     *
  676.     * @access   public
  677.     * @return   string  URL producing the response
  678.     */
  679.     function key()
  680.     {
  681.         return $this->_responses[$this->_idx]['url'];
  682.     }
  683.  
  684.  
  685.    /**
  686.     * Moves forward to next element
  687.     *
  688.     * @access   public
  689.     */ 
  690.     function next()
  691.     {
  692.         $this->_idx++;
  693.     }
  694.  
  695.  
  696.    /**
  697.     * Rewinds to the first element (response)
  698.     *
  699.     * @access   public
  700.     */
  701.     function rewind()
  702.     {
  703.         $this->_idx = 0;
  704.     }
  705.  
  706.  
  707.    /**
  708.     * Checks if there is a current element after call to rewind() or next()
  709.     *
  710.     * @access   public
  711.     * @return   bool 
  712.     */ 
  713.     function valid()
  714.     {
  715.         return $this->_idx count($this->_responses);
  716.     }
  717. }
  718. ?>

Documentation generated on Sat, 25 Oct 2008 13:30:15 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.