<?php /** * Base include file for SimpleTest * @package SimpleTest * @subpackage WebTester * @version $Id$ */ /**#@+ * include other SimpleTest class files */ require_once(dirname(__FILE__) . '/cookies.php'); require_once(dirname(__FILE__) . '/http.php'); require_once(dirname(__FILE__) . '/encoding.php'); require_once(dirname(__FILE__) . '/authentication.php'); /**#@-*/ if (! defined('DEFAULT_MAX_REDIRECTS')) { define('DEFAULT_MAX_REDIRECTS', 3); } if (! defined('DEFAULT_CONNECTION_TIMEOUT')) { define('DEFAULT_CONNECTION_TIMEOUT', 15); } /** * Fetches web pages whilst keeping track of * cookies and authentication. * @package SimpleTest * @subpackage WebTester */ class SimpleUserAgent { protected $_cookie_jar; protected $_cookies_enabled = true; protected $_authenticator; protected $_max_redirects = DEFAULT_MAX_REDIRECTS; protected $_proxy = false; protected $_proxy_username = false; protected $_proxy_password = false; protected $_connection_timeout = DEFAULT_CONNECTION_TIMEOUT; protected $_additional_headers = array(); /** * Starts with no cookies, realms or proxies. * @access public */ function SimpleUserAgent() { $this->_cookie_jar = new SimpleCookieJar(); $this->_authenticator = new SimpleAuthenticator(); } /** * Removes expired and temporary cookies as if * the browser was closed and re-opened. Authorisation * has to be obtained again as well. * @param string/integer $date Time when session restarted. * If omitted then all persistent * cookies are kept. * @access public */ function restart($date = false) { $this->_cookie_jar->restartSession($date); $this->_authenticator->restartSession(); } /** * Adds a header to every fetch. * @param string $header Header line to add to every * request until cleared. * @access public */ function addHeader($header) { $this->_additional_headers[] = $header; } /** * Ages the cookies by the specified time. * @param integer $interval Amount in seconds. * @access public */ function ageCookies($interval) { $this->_cookie_jar->agePrematurely($interval); } /** * Sets an additional cookie. If a cookie has * the same name and path it is replaced. * @param string $name Cookie key. * @param string $value Value of cookie. * @param string $host Host upon which the cookie is valid. * @param string $path Cookie path if not host wide. * @param string $expiry Expiry date. * @access public */ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) { $this->_cookie_jar->setCookie($name, $value, $host, $path, $expiry); } /** * Reads the most specific cookie value from the * browser cookies. * @param string $host Host to search. * @param string $path Applicable path. * @param string $name Name of cookie to read. * @return string False if not present, else the * value as a string. * @access public */ function getCookieValue($host, $path, $name) { return $this->_cookie_jar->getCookieValue($host, $path, $name); } /** * Reads the current cookies within the base URL. * @param string $name Key of cookie to find. * @param SimpleUrl $base Base URL to search from. * @return string/boolean Null if there is no base URL, false * if the cookie is not set. * @access public */ function getBaseCookieValue($name, $base) { if (! $base) { return null; } return $this->getCookieValue($base->getHost(), $base->getPath(), $name); } /** * Switches off cookie sending and recieving. * @access public */ function ignoreCookies() { $this->_cookies_enabled = false; } /** * Switches back on the cookie sending and recieving. * @access public */ function useCookies() { $this->_cookies_enabled = true; } /** * Sets the socket timeout for opening a connection. * @param integer $timeout Maximum time in seconds. * @access public */ function setConnectionTimeout($timeout) { $this->_connection_timeout = $timeout; } /** * Sets the maximum number of redirects before * a page will be loaded anyway. * @param integer $max Most hops allowed. * @access public */ function setMaximumRedirects($max) { $this->_max_redirects = $max; } /** * Sets proxy to use on all requests for when * testing from behind a firewall. Set URL * to false to disable. * @param string $proxy Proxy URL. * @param string $username Proxy username for authentication. * @param string $password Proxy password for authentication. * @access public */ function useProxy($proxy, $username, $password) { if (! $proxy) { $this->_proxy = false; return; } if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) { $proxy = 'http://'. $proxy; } $this->_proxy = new SimpleUrl($proxy); $this->_proxy_username = $username; $this->_proxy_password = $password; } /** * Test to see if the redirect limit is passed. * @param integer $redirects Count so far. * @return boolean True if over. * @access private */ function _isTooManyRedirects($redirects) { return ($redirects > $this->_max_redirects); } /** * Sets the identity for the current realm. * @param string $host Host to which realm applies. * @param string $realm Full name of realm. * @param string $username Username for realm. * @param string $password Password for realm. * @access public */ function setIdentity($host, $realm, $username, $password) { $this->_authenticator->setIdentityForRealm($host, $realm, $username, $password); } /** * Fetches a URL as a response object. Will keep trying if redirected. * It will also collect authentication realm information. * @param string/SimpleUrl $url Target to fetch. * @param SimpleEncoding $encoding Additional parameters for request. * @return SimpleHttpResponse Hopefully the target page. * @access public */ function &fetchResponse($url, $encoding) { if ($encoding->getMethod() != 'POST') { $url->addRequestParameters($encoding); $encoding->clear(); } $response = $this->_fetchWhileRedirected($url, $encoding); if ($headers = $response->getHeaders()) { if ($headers->isChallenge()) { $this->_authenticator->addRealm( $url, $headers->getAuthentication(), $headers->getRealm()); } } return $response; } /** * Fetches the page until no longer redirected or * until the redirect limit runs out. * @param SimpleUrl $url Target to fetch. * @param SimpelFormEncoding $encoding Additional parameters for request. * @return SimpleHttpResponse Hopefully the target page. * @access private */ function &_fetchWhileRedirected($url, $encoding) { $redirects = 0; do { $response = $this->_fetch($url, $encoding); if ($response->isError()) { return $response; } $headers = $response->getHeaders(); $location = new SimpleUrl($headers->getLocation()); $url = $location->makeAbsolute($url); if ($this->_cookies_enabled) { $headers->writeCookiesToJar($this->_cookie_jar, $url); } if (! $headers->isRedirect()) { break; } $encoding = new SimpleGetEncoding(); } while (! $this->_isTooManyRedirects(++$redirects)); return $response; } /** * Actually make the web request. * @param SimpleUrl $url Target to fetch. * @param SimpleFormEncoding $encoding Additional parameters for request. * @return SimpleHttpResponse Headers and hopefully content. * @access protected */ function &_fetch($url, $encoding) { $request = $this->_createRequest($url, $encoding); $response = $request->fetch($this->_connection_timeout); return $response; } /** * Creates a full page request. * @param SimpleUrl $url Target to fetch as url object. * @param SimpleFormEncoding $encoding POST/GET parameters. * @return SimpleHttpRequest New request. * @access private */ function &_createRequest($url, $encoding) { $request = $this->_createHttpRequest($url, $encoding); $this->_addAdditionalHeaders($request); if ($this->_cookies_enabled) { $request->readCookiesFromJar($this->_cookie_jar, $url); } $this->_authenticator->addHeaders($request, $url); return $request; } /** * Builds the appropriate HTTP request object. * @param SimpleUrl $url Target to fetch as url object. * @param SimpleFormEncoding $parameters POST/GET parameters. * @return SimpleHttpRequest New request object. * @access protected */ function &_createHttpRequest($url, $encoding) { $request = new SimpleHttpRequest($this->_createRoute($url), $encoding); return $request; } /** * Sets up either a direct route or via a proxy. * @param SimpleUrl $url Target to fetch as url object. * @return SimpleRoute Route to take to fetch URL. * @access protected */ function &_createRoute($url) { if ($this->_proxy) { $route = new SimpleProxyRoute( $url, $this->_proxy, $this->_proxy_username, $this->_proxy_password); } else { $route = new SimpleRoute($url); } return $route; } /** * Adds additional manual headers. * @param SimpleHttpRequest $request Outgoing request. * @access private */ function _addAdditionalHeaders($request) { foreach ($this->_additional_headers as $header) { $request->addHeaderLine($header); } } } ?>