PostfixAdmin - web based virtual user administration interface for Postfix mail servers https://postfixadmin.github.io/postfixadmin/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1096 lines
39 KiB

  1. <?php
  2. /**
  3. * Base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage WebTester
  6. * @version $Id: browser.php,v 1.163 2006/05/13 14:37:16 lastcraft Exp $
  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. }
  313. /**
  314. * Removes expired and temporary cookies as if
  315. * the browser was closed and re-opened.
  316. * @param string/integer $date Time when session restarted.
  317. * If omitted then all persistent
  318. * cookies are kept.
  319. * @access public
  320. */
  321. function restart($date = false) {
  322. $this->_user_agent->restart($date);
  323. }
  324. /**
  325. * Adds a header to every fetch.
  326. * @param string $header Header line to add to every
  327. * request until cleared.
  328. * @access public
  329. */
  330. function addHeader($header) {
  331. $this->_user_agent->addHeader($header);
  332. }
  333. /**
  334. * Ages the cookies by the specified time.
  335. * @param integer $interval Amount in seconds.
  336. * @access public
  337. */
  338. function ageCookies($interval) {
  339. $this->_user_agent->ageCookies($interval);
  340. }
  341. /**
  342. * Sets an additional cookie. If a cookie has
  343. * the same name and path it is replaced.
  344. * @param string $name Cookie key.
  345. * @param string $value Value of cookie.
  346. * @param string $host Host upon which the cookie is valid.
  347. * @param string $path Cookie path if not host wide.
  348. * @param string $expiry Expiry date.
  349. * @access public
  350. */
  351. function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
  352. $this->_user_agent->setCookie($name, $value, $host, $path, $expiry);
  353. }
  354. /**
  355. * Reads the most specific cookie value from the
  356. * browser cookies.
  357. * @param string $host Host to search.
  358. * @param string $path Applicable path.
  359. * @param string $name Name of cookie to read.
  360. * @return string False if not present, else the
  361. * value as a string.
  362. * @access public
  363. */
  364. function getCookieValue($host, $path, $name) {
  365. return $this->_user_agent->getCookieValue($host, $path, $name);
  366. }
  367. /**
  368. * Reads the current cookies for the current URL.
  369. * @param string $name Key of cookie to find.
  370. * @return string Null if there is no current URL, false
  371. * if the cookie is not set.
  372. * @access public
  373. */
  374. function getCurrentCookieValue($name) {
  375. return $this->_user_agent->getBaseCookieValue($name, $this->_page->getUrl());
  376. }
  377. /**
  378. * Sets the maximum number of redirects before
  379. * a page will be loaded anyway.
  380. * @param integer $max Most hops allowed.
  381. * @access public
  382. */
  383. function setMaximumRedirects($max) {
  384. $this->_user_agent->setMaximumRedirects($max);
  385. }
  386. /**
  387. * Sets the maximum number of nesting of framed pages
  388. * within a framed page to prevent loops.
  389. * @param integer $max Highest depth allowed.
  390. * @access public
  391. */
  392. function setMaximumNestedFrames($max) {
  393. $this->_maximum_nested_frames = $max;
  394. }
  395. /**
  396. * Sets the socket timeout for opening a connection.
  397. * @param integer $timeout Maximum time in seconds.
  398. * @access public
  399. */
  400. function setConnectionTimeout($timeout) {
  401. $this->_user_agent->setConnectionTimeout($timeout);
  402. }
  403. /**
  404. * Sets proxy to use on all requests for when
  405. * testing from behind a firewall. Set URL
  406. * to false to disable.
  407. * @param string $proxy Proxy URL.
  408. * @param string $username Proxy username for authentication.
  409. * @param string $password Proxy password for authentication.
  410. * @access public
  411. */
  412. function useProxy($proxy, $username = false, $password = false) {
  413. $this->_user_agent->useProxy($proxy, $username, $password);
  414. }
  415. /**
  416. * Fetches the page content with a HEAD request.
  417. * Will affect cookies, but will not change the base URL.
  418. * @param string/SimpleUrl $url Target to fetch as string.
  419. * @param hash/SimpleHeadEncoding $parameters Additional parameters for
  420. * HEAD request.
  421. * @return boolean True if successful.
  422. * @access public
  423. */
  424. function head($url, $parameters = false) {
  425. if (! is_object($url)) {
  426. $url = new SimpleUrl($url);
  427. }
  428. if ($this->getUrl()) {
  429. $url = $url->makeAbsolute($this->getUrl());
  430. }
  431. $response = &$this->_user_agent->fetchResponse($url, new SimpleHeadEncoding($parameters));
  432. return ! $response->isError();
  433. }
  434. /**
  435. * Fetches the page content with a simple GET request.
  436. * @param string/SimpleUrl $url Target to fetch.
  437. * @param hash/SimpleFormEncoding $parameters Additional parameters for
  438. * GET request.
  439. * @return string Content of page or false.
  440. * @access public
  441. */
  442. function get($url, $parameters = false) {
  443. if (! is_object($url)) {
  444. $url = new SimpleUrl($url);
  445. }
  446. if ($this->getUrl()) {
  447. $url = $url->makeAbsolute($this->getUrl());
  448. }
  449. return $this->_load($url, new SimpleGetEncoding($parameters));
  450. }
  451. /**
  452. * Fetches the page content with a POST request.
  453. * @param string/SimpleUrl $url Target to fetch as string.
  454. * @param hash/SimpleFormEncoding $parameters POST parameters.
  455. * @return string Content of page.
  456. * @access public
  457. */
  458. function post($url, $parameters = false) {
  459. if (! is_object($url)) {
  460. $url = new SimpleUrl($url);
  461. }
  462. if ($this->getUrl()) {
  463. $url = $url->makeAbsolute($this->getUrl());
  464. }
  465. return $this->_load($url, new SimplePostEncoding($parameters));
  466. }
  467. /**
  468. * Equivalent to hitting the retry button on the
  469. * browser. Will attempt to repeat the page fetch. If
  470. * there is no history to repeat it will give false.
  471. * @return string/boolean Content if fetch succeeded
  472. * else false.
  473. * @access public
  474. */
  475. function retry() {
  476. $frames = $this->_page->getFrameFocus();
  477. if (count($frames) > 0) {
  478. $this->_loadFrame(
  479. $frames,
  480. $this->_page->getUrl(),
  481. $this->_page->getRequestData());
  482. return $this->_page->getRaw();
  483. }
  484. if ($url = $this->_history->getUrl()) {
  485. $this->_page = &$this->_fetch($url, $this->_history->getParameters());
  486. return $this->_page->getRaw();
  487. }
  488. return false;
  489. }
  490. /**
  491. * Equivalent to hitting the back button on the
  492. * browser. The browser history is unchanged on
  493. * failure. The page content is refetched as there
  494. * is no concept of content caching in SimpleTest.
  495. * @return boolean True if history entry and
  496. * fetch succeeded
  497. * @access public
  498. */
  499. function back() {
  500. if (! $this->_history->back()) {
  501. return false;
  502. }
  503. $content = $this->retry();
  504. if (! $content) {
  505. $this->_history->forward();
  506. }
  507. return $content;
  508. }
  509. /**
  510. * Equivalent to hitting the forward button on the
  511. * browser. The browser history is unchanged on
  512. * failure. The page content is refetched as there
  513. * is no concept of content caching in SimpleTest.
  514. * @return boolean True if history entry and
  515. * fetch succeeded
  516. * @access public
  517. */
  518. function forward() {
  519. if (! $this->_history->forward()) {
  520. return false;
  521. }
  522. $content = $this->retry();
  523. if (! $content) {
  524. $this->_history->back();
  525. }
  526. return $content;
  527. }
  528. /**
  529. * Retries a request after setting the authentication
  530. * for the current realm.
  531. * @param string $username Username for realm.
  532. * @param string $password Password for realm.
  533. * @return boolean True if successful fetch. Note
  534. * that authentication may still have
  535. * failed.
  536. * @access public
  537. */
  538. function authenticate($username, $password) {
  539. if (! $this->_page->getRealm()) {
  540. return false;
  541. }
  542. $url = $this->_page->getUrl();
  543. if (! $url) {
  544. return false;
  545. }
  546. $this->_user_agent->setIdentity(
  547. $url->getHost(),
  548. $this->_page->getRealm(),
  549. $username,
  550. $password);
  551. return $this->retry();
  552. }
  553. /**
  554. * Accessor for a breakdown of the frameset.
  555. * @return array Hash tree of frames by name
  556. * or index if no name.
  557. * @access public
  558. */
  559. function getFrames() {
  560. return $this->_page->getFrames();
  561. }
  562. /**
  563. * Accessor for current frame focus. Will be
  564. * false if no frame has focus.
  565. * @return integer/string/boolean Label if any, otherwise
  566. * the position in the frameset
  567. * or false if none.
  568. * @access public
  569. */
  570. function getFrameFocus() {
  571. return $this->_page->getFrameFocus();
  572. }
  573. /**
  574. * Sets the focus by index. The integer index starts from 1.
  575. * @param integer $choice Chosen frame.
  576. * @return boolean True if frame exists.
  577. * @access public
  578. */
  579. function setFrameFocusByIndex($choice) {
  580. return $this->_page->setFrameFocusByIndex($choice);
  581. }
  582. /**
  583. * Sets the focus by name.
  584. * @param string $name Chosen frame.
  585. * @return boolean True if frame exists.
  586. * @access public
  587. */
  588. function setFrameFocus($name) {
  589. return $this->_page->setFrameFocus($name);
  590. }
  591. /**
  592. * Clears the frame focus. All frames will be searched
  593. * for content.
  594. * @access public
  595. */
  596. function clearFrameFocus() {
  597. return $this->_page->clearFrameFocus();
  598. }
  599. /**
  600. * Accessor for last error.
  601. * @return string Error from last response.
  602. * @access public
  603. */
  604. function getTransportError() {
  605. return $this->_page->getTransportError();
  606. }
  607. /**
  608. * Accessor for current MIME type.
  609. * @return string MIME type as string; e.g. 'text/html'
  610. * @access public
  611. */
  612. function getMimeType() {
  613. return $this->_page->getMimeType();
  614. }
  615. /**
  616. * Accessor for last response code.
  617. * @return integer Last HTTP response code received.
  618. * @access public
  619. */
  620. function getResponseCode() {
  621. return $this->_page->getResponseCode();
  622. }
  623. /**
  624. * Accessor for last Authentication type. Only valid
  625. * straight after a challenge (401).
  626. * @return string Description of challenge type.
  627. * @access public
  628. */
  629. function getAuthentication() {
  630. return $this->_page->getAuthentication();
  631. }
  632. /**
  633. * Accessor for last Authentication realm. Only valid
  634. * straight after a challenge (401).
  635. * @return string Name of security realm.
  636. * @access public
  637. */
  638. function getRealm() {
  639. return $this->_page->getRealm();
  640. }
  641. /**
  642. * Accessor for current URL of page or frame if
  643. * focused.
  644. * @return string Location of current page or frame as
  645. * a string.
  646. */
  647. function getUrl() {
  648. $url = $this->_page->getUrl();
  649. return $url ? $url->asString() : false;
  650. }
  651. /**
  652. * Accessor for raw bytes sent down the wire.
  653. * @return string Original text sent.
  654. * @access public
  655. */
  656. function getRequest() {
  657. return $this->_page->getRequest();
  658. }
  659. /**
  660. * Accessor for raw header information.
  661. * @return string Header block.
  662. * @access public
  663. */
  664. function getHeaders() {
  665. return $this->_page->getHeaders();
  666. }
  667. /**
  668. * Accessor for raw page information.
  669. * @return string Original text content of web page.
  670. * @access public
  671. */
  672. function getContent() {
  673. return $this->_page->getRaw();
  674. }
  675. /**
  676. * Accessor for plain text version of the page.
  677. * @return string Normalised text representation.
  678. * @access public
  679. */
  680. function getContentAsText() {
  681. return $this->_page->getText();
  682. }
  683. /**
  684. * Accessor for parsed title.
  685. * @return string Title or false if no title is present.
  686. * @access public
  687. */
  688. function getTitle() {
  689. return $this->_page->getTitle();
  690. }
  691. /**
  692. * Accessor for a list of all fixed links in current page.
  693. * @return array List of urls with scheme of
  694. * http or https and hostname.
  695. * @access public
  696. */
  697. function getAbsoluteUrls() {
  698. return $this->_page->getAbsoluteUrls();
  699. }
  700. /**
  701. * Accessor for a list of all relative links.
  702. * @return array List of urls without hostname.
  703. * @access public
  704. */
  705. function getRelativeUrls() {
  706. return $this->_page->getRelativeUrls();
  707. }
  708. /**
  709. * Sets all form fields with that name.
  710. * @param string $label Name or label of field in forms.
  711. * @param string $value New value of field.
  712. * @return boolean True if field exists, otherwise false.
  713. * @access public
  714. */
  715. function setField($label, $value) {
  716. return $this->_page->setField(new SimpleByLabelOrName($label), $value);
  717. }
  718. /**
  719. * Sets all form fields with that name. Will use label if
  720. * one is available (not yet implemented).
  721. * @param string $name Name of field in forms.
  722. * @param string $value New value of field.
  723. * @return boolean True if field exists, otherwise false.
  724. * @access public
  725. */
  726. function setFieldByName($name, $value) {
  727. return $this->_page->setField(new SimpleByName($name), $value);
  728. }
  729. /**
  730. * Sets all form fields with that id attribute.
  731. * @param string/integer $id Id of field in forms.
  732. * @param string $value New value of field.
  733. * @return boolean True if field exists, otherwise false.
  734. * @access public
  735. */
  736. function setFieldById($id, $value) {
  737. return $this->_page->setField(new SimpleById($id), $value);
  738. }
  739. /**
  740. * Accessor for a form element value within the page.
  741. * Finds the first match.
  742. * @param string $label Field label.
  743. * @return string/boolean A value if the field is
  744. * present, false if unchecked
  745. * and null if missing.
  746. * @access public
  747. */
  748. function getField($label) {
  749. return $this->_page->getField(new SimpleByLabelOrName($label));
  750. }
  751. /**
  752. * Accessor for a form element value within the page.
  753. * Finds the first match.
  754. * @param string $name Field name.
  755. * @return string/boolean A string if the field is
  756. * present, false if unchecked
  757. * and null if missing.
  758. * @access public
  759. */
  760. function getFieldByName($name) {
  761. return $this->_page->getField(new SimpleByName($name));
  762. }
  763. /**
  764. * Accessor for a form element value within the page.
  765. * @param string/integer $id Id of field in forms.
  766. * @return string/boolean A string if the field is
  767. * present, false if unchecked
  768. * and null if missing.
  769. * @access public
  770. */
  771. function getFieldById($id) {
  772. return $this->_page->getField(new SimpleById($id));
  773. }
  774. /**
  775. * Clicks the submit button by label. The owning
  776. * form will be submitted by this.
  777. * @param string $label Button label. An unlabeled
  778. * button can be triggered by 'Submit'.
  779. * @param hash $additional Additional form data.
  780. * @return string/boolean Page on success.
  781. * @access public
  782. */
  783. function clickSubmit($label = 'Submit', $additional = false) {
  784. if (! ($form = &$this->_page->getFormBySubmit(new SimpleByLabel($label)))) {
  785. return false;
  786. }
  787. $success = $this->_load(
  788. $form->getAction(),
  789. $form->submitButton(new SimpleByLabel($label), $additional));
  790. return ($success ? $this->getContent() : $success);
  791. }
  792. /**
  793. * Clicks the submit button by name attribute. The owning
  794. * form will be submitted by this.
  795. * @param string $name Button name.
  796. * @param hash $additional Additional form data.
  797. * @return string/boolean Page on success.
  798. * @access public
  799. */
  800. function clickSubmitByName($name, $additional = false) {
  801. if (! ($form = &$this->_page->getFormBySubmit(new SimpleByName($name)))) {
  802. return false;
  803. }
  804. $success = $this->_load(
  805. $form->getAction(),
  806. $form->submitButton(new SimpleByName($name), $additional));
  807. return ($success ? $this->getContent() : $success);
  808. }
  809. /**
  810. * Clicks the submit button by ID attribute of the button
  811. * itself. The owning form will be submitted by this.
  812. * @param string $id Button ID.
  813. * @param hash $additional Additional form data.
  814. * @return string/boolean Page on success.
  815. * @access public
  816. */
  817. function clickSubmitById($id, $additional = false) {
  818. if (! ($form = &$this->_page->getFormBySubmit(new SimpleById($id)))) {
  819. return false;
  820. }
  821. $success = $this->_load(
  822. $form->getAction(),
  823. $form->submitButton(new SimpleById($id), $additional));
  824. return ($success ? $this->getContent() : $success);
  825. }
  826. /**
  827. * Tests to see if a submit button exists with this
  828. * label.
  829. * @param string $label Button label.
  830. * @return boolean True if present.
  831. * @access public
  832. */
  833. function isSubmit($label) {
  834. return (boolean)$this->_page->getFormBySubmit(new SimpleByLabel($label));
  835. }
  836. /**
  837. * Clicks the submit image by some kind of label. Usually
  838. * the alt tag or the nearest equivalent. The owning
  839. * form will be submitted by this. Clicking outside of
  840. * the boundary of the coordinates will result in
  841. * a failure.
  842. * @param string $label ID attribute of button.
  843. * @param integer $x X-coordinate of imaginary click.
  844. * @param integer $y Y-coordinate of imaginary click.
  845. * @param hash $additional Additional form data.
  846. * @return string/boolean Page on success.
  847. * @access public
  848. */
  849. function clickImage($label, $x = 1, $y = 1, $additional = false) {
  850. if (! ($form = &$this->_page->getFormByImage(new SimpleByLabel($label)))) {
  851. return false;
  852. }
  853. $success = $this->_load(
  854. $form->getAction(),
  855. $form->submitImage(new SimpleByLabel($label), $x, $y, $additional));
  856. return ($success ? $this->getContent() : $success);
  857. }
  858. /**
  859. * Clicks the submit image by the name. Usually
  860. * the alt tag or the nearest equivalent. The owning
  861. * form will be submitted by this. Clicking outside of
  862. * the boundary of the coordinates will result in
  863. * a failure.
  864. * @param string $name Name attribute of button.
  865. * @param integer $x X-coordinate of imaginary click.
  866. * @param integer $y Y-coordinate of imaginary click.
  867. * @param hash $additional Additional form data.
  868. * @return string/boolean Page on success.
  869. * @access public
  870. */
  871. function clickImageByName($name, $x = 1, $y = 1, $additional = false) {
  872. if (! ($form = &$this->_page->getFormByImage(new SimpleByName($name)))) {
  873. return false;
  874. }
  875. $success = $this->_load(
  876. $form->getAction(),
  877. $form->submitImage(new SimpleByName($name), $x, $y, $additional));
  878. return ($success ? $this->getContent() : $success);
  879. }
  880. /**
  881. * Clicks the submit image by ID attribute. The owning
  882. * form will be submitted by this. Clicking outside of
  883. * the boundary of the coordinates will result in
  884. * a failure.
  885. * @param integer/string $id ID attribute of button.
  886. * @param integer $x X-coordinate of imaginary click.
  887. * @param integer $y Y-coordinate of imaginary click.
  888. * @param hash $additional Additional form data.
  889. * @return string/boolean Page on success.
  890. * @access public
  891. */
  892. function clickImageById($id, $x = 1, $y = 1, $additional = false) {
  893. if (! ($form = &$this->_page->getFormByImage(new SimpleById($id)))) {
  894. return false;
  895. }
  896. $success = $this->_load(
  897. $form->getAction(),
  898. $form->submitImage(new SimpleById($id), $x, $y, $additional));
  899. return ($success ? $this->getContent() : $success);
  900. }
  901. /**
  902. * Tests to see if an image exists with this
  903. * title or alt text.
  904. * @param string $label Image text.
  905. * @return boolean True if present.
  906. * @access public
  907. */
  908. function isImage($label) {
  909. return (boolean)$this->_page->getFormByImage(new SimpleByLabel($label));
  910. }
  911. /**
  912. * Submits a form by the ID.
  913. * @param string $id The form ID. No submit button value
  914. * will be sent.
  915. * @return string/boolean Page on success.
  916. * @access public
  917. */
  918. function submitFormById($id) {
  919. if (! ($form = &$this->_page->getFormById($id))) {
  920. return false;
  921. }
  922. $success = $this->_load(
  923. $form->getAction(),
  924. $form->submit());
  925. return ($success ? $this->getContent() : $success);
  926. }
  927. /**
  928. * Finds a URL by label. Will find the first link
  929. * found with this link text by default, or a later
  930. * one if an index is given. The match ignores case and
  931. * white space issues.
  932. * @param string $label Text between the anchor tags.
  933. * @param integer $index Link position counting from zero.
  934. * @return string/boolean URL on success.
  935. * @access public
  936. */
  937. function getLink($label, $index = 0) {
  938. $urls = $this->_page->getUrlsByLabel($label);
  939. if (count($urls) == 0) {
  940. return false;
  941. }
  942. if (count($urls) < $index + 1) {
  943. return false;
  944. }
  945. return $urls[$index];
  946. }
  947. /**
  948. * Follows a link by label. Will click the first link
  949. * found with this link text by default, or a later
  950. * one if an index is given. The match ignores case and
  951. * white space issues.
  952. * @param string $label Text between the anchor tags.
  953. * @param integer $index Link position counting from zero.
  954. * @return string/boolean Page on success.
  955. * @access public
  956. */
  957. function clickLink($label, $index = 0) {
  958. $url = $this->getLink($label, $index);
  959. if ($url === false) {
  960. return false;
  961. }
  962. $this->_load($url, new SimpleGetEncoding());
  963. return $this->getContent();
  964. }
  965. /**
  966. * Finds a link by id attribute.
  967. * @param string $id ID attribute value.
  968. * @return string/boolean URL on success.
  969. * @access public
  970. */
  971. function getLinkById($id) {
  972. return $this->_page->getUrlById($id);
  973. }
  974. /**
  975. * Follows a link by id attribute.
  976. * @param string $id ID attribute value.
  977. * @return string/boolean Page on success.
  978. * @access public
  979. */
  980. function clickLinkById($id) {
  981. if (! ($url = $this->getLinkById($id))) {
  982. return false;
  983. }
  984. $this->_load($url, new SimpleGetEncoding());
  985. return $this->getContent();
  986. }
  987. /**
  988. * Clicks a visible text item. Will first try buttons,
  989. * then links and then images.
  990. * @param string $label Visible text or alt text.
  991. * @return string/boolean Raw page or false.
  992. * @access public
  993. */
  994. function click($label) {
  995. $raw = $this->clickSubmit($label);
  996. if (! $raw) {
  997. $raw = $this->clickLink($label);
  998. }
  999. if (! $raw) {
  1000. $raw = $this->clickImage($label);
  1001. }
  1002. return $raw;
  1003. }
  1004. /**
  1005. * Tests to see if a click target exists.
  1006. * @param string $label Visible text or alt text.
  1007. * @return boolean True if target present.
  1008. * @access public
  1009. */
  1010. function isClickable($label) {
  1011. return $this->isSubmit($label) || ($this->getLink($label) !== false) || $this->isImage($label);
  1012. }
  1013. }
  1014. ?>