browser.php 35KB

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