browser.php 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. <?php
  2. /**
  3. * Base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage WebTester
  6. * @version $Id: browser.php 2013 2011-04-29 09:29:45Z pp11 $
  7. */
  8. /**#@+
  9. * include other SimpleTest class files
  10. */
  11. require_once(dirname(__FILE__) . '/simpletest.php');
  12. require_once(dirname(__FILE__) . '/http.php');
  13. require_once(dirname(__FILE__) . '/encoding.php');
  14. require_once(dirname(__FILE__) . '/page.php');
  15. require_once(dirname(__FILE__) . '/php_parser.php');
  16. require_once(dirname(__FILE__) . '/tidy_parser.php');
  17. require_once(dirname(__FILE__) . '/selector.php');
  18. require_once(dirname(__FILE__) . '/frames.php');
  19. require_once(dirname(__FILE__) . '/user_agent.php');
  20. if (! SimpleTest::getParsers()) {
  21. SimpleTest::setParsers(array(new SimpleTidyPageBuilder(), new SimplePHPPageBuilder()));
  22. //SimpleTest::setParsers(array(new SimplePHPPageBuilder()));
  23. }
  24. /**#@-*/
  25. if (! defined('DEFAULT_MAX_NESTED_FRAMES')) {
  26. define('DEFAULT_MAX_NESTED_FRAMES', 3);
  27. }
  28. /**
  29. * Browser history list.
  30. * @package SimpleTest
  31. * @subpackage WebTester
  32. */
  33. class SimpleBrowserHistory {
  34. private $sequence = array();
  35. private $position = -1;
  36. /**
  37. * Test for no entries yet.
  38. * @return boolean True if empty.
  39. * @access private
  40. */
  41. protected function isEmpty() {
  42. return ($this->position == -1);
  43. }
  44. /**
  45. * Test for being at the beginning.
  46. * @return boolean True if first.
  47. * @access private
  48. */
  49. protected function atBeginning() {
  50. return ($this->position == 0) && ! $this->isEmpty();
  51. }
  52. /**
  53. * Test for being at the last entry.
  54. * @return boolean True if last.
  55. * @access private
  56. */
  57. protected function atEnd() {
  58. return ($this->position + 1 >= count($this->sequence)) && ! $this->isEmpty();
  59. }
  60. /**
  61. * Adds a successfully fetched page to the history.
  62. * @param SimpleUrl $url URL of fetch.
  63. * @param SimpleEncoding $parameters Any post data with the fetch.
  64. * @access public
  65. */
  66. function recordEntry($url, $parameters) {
  67. $this->dropFuture();
  68. array_push(
  69. $this->sequence,
  70. array('url' => $url, 'parameters' => $parameters));
  71. $this->position++;
  72. }
  73. /**
  74. * Last fully qualified URL for current history
  75. * position.
  76. * @return SimpleUrl URL for this position.
  77. * @access public
  78. */
  79. function getUrl() {
  80. if ($this->isEmpty()) {
  81. return false;
  82. }
  83. return $this->sequence[$this->position]['url'];
  84. }
  85. /**
  86. * Parameters of last fetch from current history
  87. * position.
  88. * @return SimpleFormEncoding Post parameters.
  89. * @access public
  90. */
  91. function getParameters() {
  92. if ($this->isEmpty()) {
  93. return false;
  94. }
  95. return $this->sequence[$this->position]['parameters'];
  96. }
  97. /**
  98. * Step back one place in the history. Stops at
  99. * the first page.
  100. * @return boolean True if any previous entries.
  101. * @access public
  102. */
  103. function back() {
  104. if ($this->isEmpty() || $this->atBeginning()) {
  105. return false;
  106. }
  107. $this->position--;
  108. return true;
  109. }
  110. /**
  111. * Step forward one place. If already at the
  112. * latest entry then nothing will happen.
  113. * @return boolean True if any future entries.
  114. * @access public
  115. */
  116. function forward() {
  117. if ($this->isEmpty() || $this->atEnd()) {
  118. return false;
  119. }
  120. $this->position++;
  121. return true;
  122. }
  123. /**
  124. * Ditches all future entries beyond the current
  125. * point.
  126. * @access private
  127. */
  128. protected function dropFuture() {
  129. if ($this->isEmpty()) {
  130. return;
  131. }
  132. while (! $this->atEnd()) {
  133. array_pop($this->sequence);
  134. }
  135. }
  136. }
  137. /**
  138. * Simulated web browser. This is an aggregate of
  139. * the user agent, the HTML parsing, request history
  140. * and the last header set.
  141. * @package SimpleTest
  142. * @subpackage WebTester
  143. */
  144. class SimpleBrowser {
  145. private $user_agent;
  146. private $page;
  147. private $history;
  148. private $ignore_frames;
  149. private $maximum_nested_frames;
  150. private $parser;
  151. /**
  152. * Starts with a fresh browser with no
  153. * cookie or any other state information. The
  154. * exception is that a default proxy will be
  155. * set up if specified in the options.
  156. * @access public
  157. */
  158. function __construct() {
  159. $this->user_agent = $this->createUserAgent();
  160. $this->user_agent->useProxy(
  161. SimpleTest::getDefaultProxy(),
  162. SimpleTest::getDefaultProxyUsername(),
  163. SimpleTest::getDefaultProxyPassword());
  164. $this->page = new SimplePage();
  165. $this->history = $this->createHistory();
  166. $this->ignore_frames = false;
  167. $this->maximum_nested_frames = DEFAULT_MAX_NESTED_FRAMES;
  168. }
  169. /**
  170. * Creates the underlying user agent.
  171. * @return SimpleFetcher Content fetcher.
  172. * @access protected
  173. */
  174. protected function createUserAgent() {
  175. return new SimpleUserAgent();
  176. }
  177. /**
  178. * Creates a new empty history list.
  179. * @return SimpleBrowserHistory New list.
  180. * @access protected
  181. */
  182. protected function createHistory() {
  183. return new SimpleBrowserHistory();
  184. }
  185. /**
  186. * Get the HTML parser to use. Can be overridden by
  187. * setParser. Otherwise scans through the available parsers and
  188. * uses the first one which is available.
  189. * @return object SimplePHPPageBuilder or SimpleTidyPageBuilder
  190. */
  191. protected function getParser() {
  192. if ($this->parser) {
  193. return $this->parser;
  194. }
  195. foreach (SimpleTest::getParsers() as $parser) {
  196. if ($parser->can()) {
  197. return $parser;
  198. }
  199. }
  200. }
  201. /**
  202. * Override the default HTML parser, allowing parsers to be plugged in.
  203. * @param object A parser object instance.
  204. */
  205. public function setParser($parser) {
  206. $this->parser = $parser;
  207. }
  208. /**
  209. * Disables frames support. Frames will not be fetched
  210. * and the frameset page will be used instead.
  211. * @access public
  212. */
  213. function ignoreFrames() {
  214. $this->ignore_frames = true;
  215. }
  216. /**
  217. * Enables frames support. Frames will be fetched from
  218. * now on.
  219. * @access public
  220. */
  221. function useFrames() {
  222. $this->ignore_frames = false;
  223. }
  224. /**
  225. * Switches off cookie sending and recieving.
  226. * @access public
  227. */
  228. function ignoreCookies() {
  229. $this->user_agent->ignoreCookies();
  230. }
  231. /**
  232. * Switches back on the cookie sending and recieving.
  233. * @access public
  234. */
  235. function useCookies() {
  236. $this->user_agent->useCookies();
  237. }
  238. /**
  239. * Parses the raw content into a page. Will load further
  240. * frame pages unless frames are disabled.
  241. * @param SimpleHttpResponse $response Response from fetch.
  242. * @param integer $depth Nested frameset depth.
  243. * @return SimplePage Parsed HTML.
  244. * @access private
  245. */
  246. protected function parse($response, $depth = 0) {
  247. $page = $this->buildPage($response);
  248. if ($this->ignore_frames || ! $page->hasFrames() || ($depth > $this->maximum_nested_frames)) {
  249. return $page;
  250. }
  251. $frameset = new SimpleFrameset($page);
  252. foreach ($page->getFrameset() as $key => $url) {
  253. $frame = $this->fetch($url, new SimpleGetEncoding(), $depth + 1);
  254. $frameset->addFrame($frame, $key);
  255. }
  256. return $frameset;
  257. }
  258. /**
  259. * Assembles the parsing machinery and actually parses
  260. * a single page. Frees all of the builder memory and so
  261. * unjams the PHP memory management.
  262. * @param SimpleHttpResponse $response Response from fetch.
  263. * @return SimplePage Parsed top level page.
  264. */
  265. protected function buildPage($response) {
  266. return $this->getParser()->parse($response);
  267. }
  268. /**
  269. * Fetches a page. Jointly recursive with the parse()
  270. * method as it descends a frameset.
  271. * @param string/SimpleUrl $url Target to fetch.
  272. * @param SimpleEncoding $encoding GET/POST parameters.
  273. * @param integer $depth Nested frameset depth protection.
  274. * @return SimplePage Parsed page.
  275. * @access private
  276. */
  277. protected function fetch($url, $encoding, $depth = 0) {
  278. $response = $this->user_agent->fetchResponse($url, $encoding);
  279. if ($response->isError()) {
  280. return new SimplePage($response);
  281. }
  282. return $this->parse($response, $depth);
  283. }
  284. /**
  285. * Fetches a page or a single frame if that is the current
  286. * focus.
  287. * @param SimpleUrl $url Target to fetch.
  288. * @param SimpleEncoding $parameters GET/POST parameters.
  289. * @return string Raw content of page.
  290. * @access private
  291. */
  292. protected function load($url, $parameters) {
  293. $frame = $url->getTarget();
  294. if (! $frame || ! $this->page->hasFrames() || (strtolower($frame) == '_top')) {
  295. return $this->loadPage($url, $parameters);
  296. }
  297. return $this->loadFrame(array($frame), $url, $parameters);
  298. }
  299. /**
  300. * Fetches a page and makes it the current page/frame.
  301. * @param string/SimpleUrl $url Target to fetch as string.
  302. * @param SimplePostEncoding $parameters POST parameters.
  303. * @return string Raw content of page.
  304. * @access private
  305. */
  306. protected function loadPage($url, $parameters) {
  307. $this->page = $this->fetch($url, $parameters);
  308. $this->history->recordEntry(
  309. $this->page->getUrl(),
  310. $this->page->getRequestData());
  311. return $this->page->getRaw();
  312. }
  313. /**
  314. * Fetches a frame into the existing frameset replacing the
  315. * original.
  316. * @param array $frames List of names to drill down.
  317. * @param string/SimpleUrl $url Target to fetch as string.
  318. * @param SimpleFormEncoding $parameters POST parameters.
  319. * @return string Raw content of page.
  320. * @access private
  321. */
  322. protected function loadFrame($frames, $url, $parameters) {
  323. $page = $this->fetch($url, $parameters);
  324. $this->page->setFrame($frames, $page);
  325. return $page->getRaw();
  326. }
  327. /**
  328. * Removes expired and temporary cookies as if
  329. * the browser was closed and re-opened.
  330. * @param string/integer $date Time when session restarted.
  331. * If omitted then all persistent
  332. * cookies are kept.
  333. * @access public
  334. */
  335. function restart($date = false) {
  336. $this->user_agent->restart($date);
  337. }
  338. /**
  339. * Adds a header to every fetch.
  340. * @param string $header Header line to add to every
  341. * request until cleared.
  342. * @access public
  343. */
  344. function addHeader($header) {
  345. $this->user_agent->addHeader($header);
  346. }
  347. /**
  348. * Ages the cookies by the specified time.
  349. * @param integer $interval Amount in seconds.
  350. * @access public
  351. */
  352. function ageCookies($interval) {
  353. $this->user_agent->ageCookies($interval);
  354. }
  355. /**
  356. * Sets an additional cookie. If a cookie has
  357. * the same name and path it is replaced.
  358. * @param string $name Cookie key.
  359. * @param string $value Value of cookie.
  360. * @param string $host Host upon which the cookie is valid.
  361. * @param string $path Cookie path if not host wide.
  362. * @param string $expiry Expiry date.
  363. * @access public
  364. */
  365. function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
  366. $this->user_agent->setCookie($name, $value, $host, $path, $expiry);
  367. }
  368. /**
  369. * Reads the most specific cookie value from the
  370. * browser cookies.
  371. * @param string $host Host to search.
  372. * @param string $path Applicable path.
  373. * @param string $name Name of cookie to read.
  374. * @return string False if not present, else the
  375. * value as a string.
  376. * @access public
  377. */
  378. function getCookieValue($host, $path, $name) {
  379. return $this->user_agent->getCookieValue($host, $path, $name);
  380. }
  381. /**
  382. * Reads the current cookies for the current URL.
  383. * @param string $name Key of cookie to find.
  384. * @return string Null if there is no current URL, false
  385. * if the cookie is not set.
  386. * @access public
  387. */
  388. function getCurrentCookieValue($name) {
  389. return $this->user_agent->getBaseCookieValue($name, $this->page->getUrl());
  390. }
  391. /**
  392. * Sets the maximum number of redirects before
  393. * a page will be loaded anyway.
  394. * @param integer $max Most hops allowed.
  395. * @access public
  396. */
  397. function setMaximumRedirects($max) {
  398. $this->user_agent->setMaximumRedirects($max);
  399. }
  400. /**
  401. * Sets the maximum number of nesting of framed pages
  402. * within a framed page to prevent loops.
  403. * @param integer $max Highest depth allowed.
  404. * @access public
  405. */
  406. function setMaximumNestedFrames($max) {
  407. $this->maximum_nested_frames = $max;
  408. }
  409. /**
  410. * Sets the socket timeout for opening a connection.
  411. * @param integer $timeout Maximum time in seconds.
  412. * @access public
  413. */
  414. function setConnectionTimeout($timeout) {
  415. $this->user_agent->setConnectionTimeout($timeout);
  416. }
  417. /**
  418. * Sets proxy to use on all requests for when
  419. * testing from behind a firewall. Set URL
  420. * to false to disable.
  421. * @param string $proxy Proxy URL.
  422. * @param string $username Proxy username for authentication.
  423. * @param string $password Proxy password for authentication.
  424. * @access public
  425. */
  426. function useProxy($proxy, $username = false, $password = false) {
  427. $this->user_agent->useProxy($proxy, $username, $password);
  428. }
  429. /**
  430. * Fetches the page content with a HEAD request.
  431. * Will affect cookies, but will not change the base URL.
  432. * @param string/SimpleUrl $url Target to fetch as string.
  433. * @param hash/SimpleHeadEncoding $parameters Additional parameters for
  434. * HEAD request.
  435. * @return boolean True if successful.
  436. * @access public
  437. */
  438. function head($url, $parameters = false) {
  439. if (! is_object($url)) {
  440. $url = new SimpleUrl($url);
  441. }
  442. if ($this->getUrl()) {
  443. $url = $url->makeAbsolute($this->getUrl());
  444. }
  445. $response = $this->user_agent->fetchResponse($url, new SimpleHeadEncoding($parameters));
  446. $this->page = new SimplePage($response);
  447. return ! $response->isError();
  448. }
  449. /**
  450. * Fetches the page content with a simple GET request.
  451. * @param string/SimpleUrl $url Target to fetch.
  452. * @param hash/SimpleFormEncoding $parameters Additional parameters for
  453. * GET request.
  454. * @return string Content of page or false.
  455. * @access public
  456. */
  457. function get($url, $parameters = false) {
  458. if (! is_object($url)) {
  459. $url = new SimpleUrl($url);
  460. }
  461. if ($this->getUrl()) {
  462. $url = $url->makeAbsolute($this->getUrl());
  463. }
  464. return $this->load($url, new SimpleGetEncoding($parameters));
  465. }
  466. /**
  467. * Fetches the page content with a POST request.
  468. * @param string/SimpleUrl $url Target to fetch as string.
  469. * @param hash/SimpleFormEncoding $parameters POST parameters or request body.
  470. * @param string $content_type MIME Content-Type of the request body
  471. * @return string Content of page.
  472. * @access public
  473. */
  474. function post($url, $parameters = false, $content_type = false) {
  475. if (! is_object($url)) {
  476. $url = new SimpleUrl($url);
  477. }
  478. if ($this->getUrl()) {
  479. $url = $url->makeAbsolute($this->getUrl());
  480. }
  481. return $this->load($url, new SimplePostEncoding($parameters, $content_type));
  482. }
  483. /**
  484. * Fetches the page content with a PUT request.
  485. * @param string/SimpleUrl $url Target to fetch as string.
  486. * @param hash/SimpleFormEncoding $parameters PUT request body.
  487. * @param string $content_type MIME Content-Type of the request body
  488. * @return string Content of page.
  489. * @access public
  490. */
  491. function put($url, $parameters = false, $content_type = false) {
  492. if (! is_object($url)) {
  493. $url = new SimpleUrl($url);
  494. }
  495. return $this->load($url, new SimplePutEncoding($parameters, $content_type));
  496. }
  497. /**
  498. * Sends a DELETE request and fetches the response.
  499. * @param string/SimpleUrl $url Target to fetch.
  500. * @param hash/SimpleFormEncoding $parameters Additional parameters for
  501. * DELETE request.
  502. * @return string Content of page or false.
  503. * @access public
  504. */
  505. function delete($url, $parameters = false) {
  506. if (! is_object($url)) {
  507. $url = new SimpleUrl($url);
  508. }
  509. return $this->load($url, new SimpleDeleteEncoding($parameters));
  510. }
  511. /**
  512. * Equivalent to hitting the retry button on the
  513. * browser. Will attempt to repeat the page fetch. If
  514. * there is no history to repeat it will give false.
  515. * @return string/boolean Content if fetch succeeded
  516. * else false.
  517. * @access public
  518. */
  519. function retry() {
  520. $frames = $this->page->getFrameFocus();
  521. if (count($frames) > 0) {
  522. $this->loadFrame(
  523. $frames,
  524. $this->page->getUrl(),
  525. $this->page->getRequestData());
  526. return $this->page->getRaw();
  527. }
  528. if ($url = $this->history->getUrl()) {
  529. $this->page = $this->fetch($url, $this->history->getParameters());
  530. return $this->page->getRaw();
  531. }
  532. return false;
  533. }
  534. /**
  535. * Equivalent to hitting the back button on the
  536. * browser. The browser history is unchanged on
  537. * failure. The page content is refetched as there
  538. * is no concept of content caching in SimpleTest.
  539. * @return boolean True if history entry and
  540. * fetch succeeded
  541. * @access public
  542. */
  543. function back() {
  544. if (! $this->history->back()) {
  545. return false;
  546. }
  547. $content = $this->retry();
  548. if (! $content) {
  549. $this->history->forward();
  550. }
  551. return $content;
  552. }
  553. /**
  554. * Equivalent to hitting the forward button on the
  555. * browser. The browser history is unchanged on
  556. * failure. The page content is refetched as there
  557. * is no concept of content caching in SimpleTest.
  558. * @return boolean True if history entry and
  559. * fetch succeeded
  560. * @access public
  561. */
  562. function forward() {
  563. if (! $this->history->forward()) {
  564. return false;
  565. }
  566. $content = $this->retry();
  567. if (! $content) {
  568. $this->history->back();
  569. }
  570. return $content;
  571. }
  572. /**
  573. * Retries a request after setting the authentication
  574. * for the current realm.
  575. * @param string $username Username for realm.
  576. * @param string $password Password for realm.
  577. * @return boolean True if successful fetch. Note
  578. * that authentication may still have
  579. * failed.
  580. * @access public
  581. */
  582. function authenticate($username, $password) {
  583. if (! $this->page->getRealm()) {
  584. return false;
  585. }
  586. $url = $this->page->getUrl();
  587. if (! $url) {
  588. return false;
  589. }
  590. $this->user_agent->setIdentity(
  591. $url->getHost(),
  592. $this->page->getRealm(),
  593. $username,
  594. $password);
  595. return $this->retry();
  596. }
  597. /**
  598. * Accessor for a breakdown of the frameset.
  599. * @return array Hash tree of frames by name
  600. * or index if no name.
  601. * @access public
  602. */
  603. function getFrames() {
  604. return $this->page->getFrames();
  605. }
  606. /**
  607. * Accessor for current frame focus. Will be
  608. * false if no frame has focus.
  609. * @return integer/string/boolean Label if any, otherwise
  610. * the position in the frameset
  611. * or false if none.
  612. * @access public
  613. */
  614. function getFrameFocus() {
  615. return $this->page->getFrameFocus();
  616. }
  617. /**
  618. * Sets the focus by index. The integer index starts from 1.
  619. * @param integer $choice Chosen frame.
  620. * @return boolean True if frame exists.
  621. * @access public
  622. */
  623. function setFrameFocusByIndex($choice) {
  624. return $this->page->setFrameFocusByIndex($choice);
  625. }
  626. /**
  627. * Sets the focus by name.
  628. * @param string $name Chosen frame.
  629. * @return boolean True if frame exists.
  630. * @access public
  631. */
  632. function setFrameFocus($name) {
  633. return $this->page->setFrameFocus($name);
  634. }
  635. /**
  636. * Clears the frame focus. All frames will be searched
  637. * for content.
  638. * @access public
  639. */
  640. function clearFrameFocus() {
  641. return $this->page->clearFrameFocus();
  642. }
  643. /**
  644. * Accessor for last error.
  645. * @return string Error from last response.
  646. * @access public
  647. */
  648. function getTransportError() {
  649. return $this->page->getTransportError();
  650. }
  651. /**
  652. * Accessor for current MIME type.
  653. * @return string MIME type as string; e.g. 'text/html'
  654. * @access public
  655. */
  656. function getMimeType() {
  657. return $this->page->getMimeType();
  658. }
  659. /**
  660. * Accessor for last response code.
  661. * @return integer Last HTTP response code received.
  662. * @access public
  663. */
  664. function getResponseCode() {
  665. return $this->page->getResponseCode();
  666. }
  667. /**
  668. * Accessor for last Authentication type. Only valid
  669. * straight after a challenge (401).
  670. * @return string Description of challenge type.
  671. * @access public
  672. */
  673. function getAuthentication() {
  674. return $this->page->getAuthentication();
  675. }
  676. /**
  677. * Accessor for last Authentication realm. Only valid
  678. * straight after a challenge (401).
  679. * @return string Name of security realm.
  680. * @access public
  681. */
  682. function getRealm() {
  683. return $this->page->getRealm();
  684. }
  685. /**
  686. * Accessor for current URL of page or frame if
  687. * focused.
  688. * @return string Location of current page or frame as
  689. * a string.
  690. */
  691. function getUrl() {
  692. $url = $this->page->getUrl();
  693. return $url ? $url->asString() : false;
  694. }
  695. /**
  696. * Accessor for base URL of page if set via BASE tag
  697. * @return string base URL
  698. */
  699. function getBaseUrl() {
  700. $url = $this->page->getBaseUrl();
  701. return $url ? $url->asString() : false;
  702. }
  703. /**
  704. * Accessor for raw bytes sent down the wire.
  705. * @return string Original text sent.
  706. * @access public
  707. */
  708. function getRequest() {
  709. return $this->page->getRequest();
  710. }
  711. /**
  712. * Accessor for raw header information.
  713. * @return string Header block.
  714. * @access public
  715. */
  716. function getHeaders() {
  717. return $this->page->getHeaders();
  718. }
  719. /**
  720. * Accessor for raw page information.
  721. * @return string Original text content of web page.
  722. * @access public
  723. */
  724. function getContent() {
  725. return $this->page->getRaw();
  726. }
  727. /**
  728. * Accessor for plain text version of the page.
  729. * @return string Normalised text representation.
  730. * @access public
  731. */
  732. function getContentAsText() {
  733. return $this->page->getText();
  734. }
  735. /**
  736. * Accessor for parsed title.
  737. * @return string Title or false if no title is present.
  738. * @access public
  739. */
  740. function getTitle() {
  741. return $this->page->getTitle();
  742. }
  743. /**
  744. * Accessor for a list of all links in current page.
  745. * @return array List of urls with scheme of
  746. * http or https and hostname.
  747. * @access public
  748. */
  749. function getUrls() {
  750. return $this->page->getUrls();
  751. }
  752. /**
  753. * Sets all form fields with that name.
  754. * @param string $label Name or label of field in forms.
  755. * @param string $value New value of field.
  756. * @return boolean True if field exists, otherwise false.
  757. * @access public
  758. */
  759. function setField($label, $value, $position=false) {
  760. return $this->page->setField(new SimpleByLabelOrName($label), $value, $position);
  761. }
  762. /**
  763. * Sets all form fields with that name. Will use label if
  764. * one is available (not yet implemented).
  765. * @param string $name Name of field in forms.
  766. * @param string $value New value of field.
  767. * @return boolean True if field exists, otherwise false.
  768. * @access public
  769. */
  770. function setFieldByName($name, $value, $position=false) {
  771. return $this->page->setField(new SimpleByName($name), $value, $position);
  772. }
  773. /**
  774. * Sets all form fields with that id attribute.
  775. * @param string/integer $id Id of field in forms.
  776. * @param string $value New value of field.
  777. * @return boolean True if field exists, otherwise false.
  778. * @access public
  779. */
  780. function setFieldById($id, $value) {
  781. return $this->page->setField(new SimpleById($id), $value);
  782. }
  783. /**
  784. * Accessor for a form element value within the page.
  785. * Finds the first match.
  786. * @param string $label Field label.
  787. * @return string/boolean A value if the field is
  788. * present, false if unchecked
  789. * and null if missing.
  790. * @access public
  791. */
  792. function getField($label) {
  793. return $this->page->getField(new SimpleByLabelOrName($label));
  794. }
  795. /**
  796. * Accessor for a form element value within the page.
  797. * Finds the first match.
  798. * @param string $name Field name.
  799. * @return string/boolean A string if the field is
  800. * present, false if unchecked
  801. * and null if missing.
  802. * @access public
  803. */
  804. function getFieldByName($name) {
  805. return $this->page->getField(new SimpleByName($name));
  806. }
  807. /**
  808. * Accessor for a form element value within the page.
  809. * @param string/integer $id Id of field in forms.
  810. * @return string/boolean A string if the field is
  811. * present, false if unchecked
  812. * and null if missing.
  813. * @access public
  814. */
  815. function getFieldById($id) {
  816. return $this->page->getField(new SimpleById($id));
  817. }
  818. /**
  819. * Clicks the submit button by label. The owning
  820. * form will be submitted by this.
  821. * @param string $label Button label. An unlabeled
  822. * button can be triggered by 'Submit'.
  823. * @param hash $additional Additional form data.
  824. * @return string/boolean Page on success.
  825. * @access public
  826. */
  827. function clickSubmit($label = 'Submit', $additional = false) {
  828. if (! ($form = $this->page->getFormBySubmit(new SimpleByLabel($label)))) {
  829. return false;
  830. }
  831. $success = $this->load(
  832. $form->getAction(),
  833. $form->submitButton(new SimpleByLabel($label), $additional));
  834. return ($success ? $this->getContent() : $success);
  835. }
  836. /**
  837. * Clicks the submit button by name attribute. The owning
  838. * form will be submitted by this.
  839. * @param string $name Button name.
  840. * @param hash $additional Additional form data.
  841. * @return string/boolean Page on success.
  842. * @access public
  843. */
  844. function clickSubmitByName($name, $additional = false) {
  845. if (! ($form = $this->page->getFormBySubmit(new SimpleByName($name)))) {
  846. return false;
  847. }
  848. $success = $this->load(
  849. $form->getAction(),
  850. $form->submitButton(new SimpleByName($name), $additional));
  851. return ($success ? $this->getContent() : $success);
  852. }
  853. /**
  854. * Clicks the submit button by ID attribute of the button
  855. * itself. The owning form will be submitted by this.
  856. * @param string $id Button ID.
  857. * @param hash $additional Additional form data.
  858. * @return string/boolean Page on success.
  859. * @access public
  860. */
  861. function clickSubmitById($id, $additional = false) {
  862. if (! ($form = $this->page->getFormBySubmit(new SimpleById($id)))) {
  863. return false;
  864. }
  865. $success = $this->load(
  866. $form->getAction(),
  867. $form->submitButton(new SimpleById($id), $additional));
  868. return ($success ? $this->getContent() : $success);
  869. }
  870. /**
  871. * Tests to see if a submit button exists with this
  872. * label.
  873. * @param string $label Button label.
  874. * @return boolean True if present.
  875. * @access public
  876. */
  877. function isSubmit($label) {
  878. return (boolean)$this->page->getFormBySubmit(new SimpleByLabel($label));
  879. }
  880. /**
  881. * Clicks the submit image by some kind of label. Usually
  882. * the alt tag or the nearest equivalent. The owning
  883. * form will be submitted by this. Clicking outside of
  884. * the boundary of the coordinates will result in
  885. * a failure.
  886. * @param string $label ID attribute of button.
  887. * @param integer $x X-coordinate of imaginary click.
  888. * @param integer $y Y-coordinate of imaginary click.
  889. * @param hash $additional Additional form data.
  890. * @return string/boolean Page on success.
  891. * @access public
  892. */
  893. function clickImage($label, $x = 1, $y = 1, $additional = false) {
  894. if (! ($form = $this->page->getFormByImage(new SimpleByLabel($label)))) {
  895. return false;
  896. }
  897. $success = $this->load(
  898. $form->getAction(),
  899. $form->submitImage(new SimpleByLabel($label), $x, $y, $additional));
  900. return ($success ? $this->getContent() : $success);
  901. }
  902. /**
  903. * Clicks the submit image by the name. Usually
  904. * the alt tag or the nearest equivalent. The owning
  905. * form will be submitted by this. Clicking outside of
  906. * the boundary of the coordinates will result in
  907. * a failure.
  908. * @param string $name Name attribute of button.
  909. * @param integer $x X-coordinate of imaginary click.
  910. * @param integer $y Y-coordinate of imaginary click.
  911. * @param hash $additional Additional form data.
  912. * @return string/boolean Page on success.
  913. * @access public
  914. */
  915. function clickImageByName($name, $x = 1, $y = 1, $additional = false) {
  916. if (! ($form = $this->page->getFormByImage(new SimpleByName($name)))) {
  917. return false;
  918. }
  919. $success = $this->load(
  920. $form->getAction(),
  921. $form->submitImage(new SimpleByName($name), $x, $y, $additional));
  922. return ($success ? $this->getContent() : $success);
  923. }
  924. /**
  925. * Clicks the submit image by ID attribute. The owning
  926. * form will be submitted by this. Clicking outside of
  927. * the boundary of the coordinates will result in
  928. * a failure.
  929. * @param integer/string $id ID attribute of button.
  930. * @param integer $x X-coordinate of imaginary click.
  931. * @param integer $y Y-coordinate of imaginary click.
  932. * @param hash $additional Additional form data.
  933. * @return string/boolean Page on success.
  934. * @access public
  935. */
  936. function clickImageById($id, $x = 1, $y = 1, $additional = false) {
  937. if (! ($form = $this->page->getFormByImage(new SimpleById($id)))) {
  938. return false;
  939. }
  940. $success = $this->load(
  941. $form->getAction(),
  942. $form->submitImage(new SimpleById($id), $x, $y, $additional));
  943. return ($success ? $this->getContent() : $success);
  944. }
  945. /**
  946. * Tests to see if an image exists with this
  947. * title or alt text.
  948. * @param string $label Image text.
  949. * @return boolean True if present.
  950. * @access public
  951. */
  952. function isImage($label) {
  953. return (boolean)$this->page->getFormByImage(new SimpleByLabel($label));
  954. }
  955. /**
  956. * Submits a form by the ID.
  957. * @param string $id The form ID. No submit button value
  958. * will be sent.
  959. * @return string/boolean Page on success.
  960. * @access public
  961. */
  962. function submitFormById($id, $additional = false) {
  963. if (! ($form = $this->page->getFormById($id))) {
  964. return false;
  965. }
  966. $success = $this->load(
  967. $form->getAction(),
  968. $form->submit($additional));
  969. return ($success ? $this->getContent() : $success);
  970. }
  971. /**
  972. * Finds a URL by label. Will find the first link
  973. * found with this link text by default, or a later
  974. * one if an index is given. The match ignores case and
  975. * white space issues.
  976. * @param string $label Text between the anchor tags.
  977. * @param integer $index Link position counting from zero.
  978. * @return string/boolean URL on success.
  979. * @access public
  980. */
  981. function getLink($label, $index = 0) {
  982. $urls = $this->page->getUrlsByLabel($label);
  983. if (count($urls) == 0) {
  984. return false;
  985. }
  986. if (count($urls) < $index + 1) {
  987. return false;
  988. }
  989. return $urls[$index];
  990. }
  991. /**
  992. * Follows a link by label. Will click the first link
  993. * found with this link text by default, or a later
  994. * one if an index is given. The match ignores case and
  995. * white space issues.
  996. * @param string $label Text between the anchor tags.
  997. * @param integer $index Link position counting from zero.
  998. * @return string/boolean Page on success.
  999. * @access public
  1000. */
  1001. function clickLink($label, $index = 0) {
  1002. $url = $this->getLink($label, $index);
  1003. if ($url === false) {
  1004. return false;
  1005. }
  1006. $this->load($url, new SimpleGetEncoding());
  1007. return $this->getContent();
  1008. }
  1009. /**
  1010. * Finds a link by id attribute.
  1011. * @param string $id ID attribute value.
  1012. * @return string/boolean URL on success.
  1013. * @access public
  1014. */
  1015. function getLinkById($id) {
  1016. return $this->page->getUrlById($id);
  1017. }
  1018. /**
  1019. * Follows a link by id attribute.
  1020. * @param string $id ID attribute value.
  1021. * @return string/boolean Page on success.
  1022. * @access public
  1023. */
  1024. function clickLinkById($id) {
  1025. if (! ($url = $this->getLinkById($id))) {
  1026. return false;
  1027. }
  1028. $this->load($url, new SimpleGetEncoding());
  1029. return $this->getContent();
  1030. }
  1031. /**
  1032. * Clicks a visible text item. Will first try buttons,
  1033. * then links and then images.
  1034. * @param string $label Visible text or alt text.
  1035. * @return string/boolean Raw page or false.
  1036. * @access public
  1037. */
  1038. function click($label) {
  1039. $raw = $this->clickSubmit($label);
  1040. if (! $raw) {
  1041. $raw = $this->clickLink($label);
  1042. }
  1043. if (! $raw) {
  1044. $raw = $this->clickImage($label);
  1045. }
  1046. return $raw;
  1047. }
  1048. /**
  1049. * Tests to see if a click target exists.
  1050. * @param string $label Visible text or alt text.
  1051. * @return boolean True if target present.
  1052. * @access public
  1053. */
  1054. function isClickable($label) {
  1055. return $this->isSubmit($label) || ($this->getLink($label) !== false) || $this->isImage($label);
  1056. }
  1057. }
  1058. ?>