browser.php 35 KB

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