Source for file class.atomapi.php

Documentation is available at class.atomapi.php

  1. <?php
  2.  
  3. /****************************************************************************\
  4. PHP Atom API Package
  5. version 1.0
  6. Includes AtomAPI, AtomFeed, AtomEntry and AtomRequest
  7. Written by Beau Lebens, 2005
  8. beau@dentedreality.com.au
  9. http://www.dentedreality.com.au/phpatomapi/
  10. More Atom Info;
  11. AtomEnabled: http://www.atomenabled.org/
  12. Atom Wiki: http://www.intertwingly.net/wiki/pie/FrontPage
  13. API Spec: http://www.atomenabled.org/developers/api/atom-api-spec.php
  14. Blog-Specific API Details
  15. Blogger: http://code.blogspot.com/archives/atom-docs.html
  16. TypePad: http://sixapart.com/developers/atom/typepad/
  17. TODO
  18. - Proper date handling (GMT, local etc)
  19. - AtomEntry::from_xml() needs work on author info handling - sample?
  20. - Complete test suite/application?
  21. \****************************************************************************/
  22.  
  23. // Error Numbers
  24. define('ATOMAPI_ENDPOINT_INVALID', 1);
  25. define('ATOMAPI_AUTHTYPE_INVALID', 2);
  26. define('ATOMAPI_AUTHENTICATION_FAILED', 3);
  27. define('ATOMAPI_NO_FEEDS', 4);
  28. define('ATOMAPI_NO_XML', 5);
  29. define('ATOMAPI_FEED_INIT_FAILED', 6);
  30. define('ATOMAPI_METHOD_INVALID', 7);
  31. define('ATOMAPI_PAYLOAD_INVALID', 8);
  32. define('ATOMAPI_REQUEST_INVALID', 9);
  33. define('ATOMAPI_CURL_ERROR', 10);
  34.  
  35. // Error Strings
  36. $ATOMAPI_ERROR_STRINGS = array(1=>'The specified AtomAPI endpoint (or request URL) is invalid. Please enter a complete URL, starting with \'http\'.',
  37. 2=>'The PHPAtomAPI Package currently only supports \'Basic\' and \'WSSE\' authentication models. Please specify one of them.',
  38. 3=>'Authentication against the AtomAPI endpoint failed. Please check your username/password.',
  39. 4=>'No feeds were located at the specified AtomAPI endpoint.',
  40. 5=>'No feeds were initiated because there was no XML available to parse.',
  41. 6=>'No feeds were initiated because the FeedURI did not respond as expected.',
  42. 7=>'An invalid method was supplied to an AtomRequest object. Methods available are GET, PUT, POST and DELETE',
  43. 8=>'The payload supplied to an AtomRequest object appears to be something other than a string. Please only supply a string as payload.',
  44. 9=>'An AtomRequest object was initiated incorrectly, and is missing either a URI or a Method.',
  45. 10=>'cURL failed to perform the required request within an AtomRequest.');
  46.  
  47. class AtomAPI {
  48. var $endpoint;
  49. var $authtype;
  50. var $auth;
  51. var $feeds;
  52. var $feed_objs;
  53. var $err_no;
  54. /**
  55. * @return AtomAPI/FALSE
  56. * @param String $endpoint
  57. * @param String $username
  58. * @param String $password
  59. * @param String $authtype
  60. * @desc Creates an AtomAPI Object, verifying authentication details by attempting to load a list of feeds. $authtype should be 'Basic' or 'WSSE'
  61. */
  62. function AtomAPI($endpoint, $username, $password, $authtype) {
  63. // Abort if the endpoint is missing
  64. if ($endpoint === false || !strlen($endpoint)) {
  65. $this->err_no = ATOMAPI_ENDPOINT_INVALID;
  66. return false;
  67. }
  68. // Set the endpoint and authtype
  69. $this->set_authtype($authtype, $username, $password);
  70. if (!$this->get_auth()) {
  71. return false;
  72. }
  73. $this->set_endpoint($endpoint);
  74. if (!$this->get_endpoint()) {
  75. return false;
  76. }
  77. // Verify authentication (and load feeds)
  78. return $this->verify_auth();
  79. }
  80. /**
  81. * @return void
  82. * @param String $uri
  83. * @desc Set the endpoint for accessing this AtomAPI. Must be a fully-qualified URI starting with 'http'
  84. */
  85. function set_endpoint($uri) {
  86. if (substr($uri, 0, 4) == 'http') {
  87. $this->endpoint = $uri;
  88. }
  89. else {
  90. $this->err_no = ATOMAPI_ENDPOINT_INVALID;
  91. }
  92. }
  93. /**
  94. * @return String/FALSE
  95. * @desc Return the endpoint set for this AtomAPI or FALSE if unset
  96. */
  97. function get_endpoint() {
  98. if (isset($this->endpoint)) {
  99. return $this->endpoint;
  100. }
  101. else {
  102. return false;
  103. }
  104. }
  105. /**
  106. * @return void
  107. * @param String $type
  108. * @param String $user
  109. * @param String $pass
  110. * @desc Creates the authentication object for this Atom API, based on the type specified. Currently supports WSSE and Basic as $type
  111. */
  112. function set_authtype($type, $user, $pass) {
  113. $this->authtype = $type;
  114. if ($type == 'Basic') {
  115. require_once(dirname(__FILE__) . '/class.basicauth.php');
  116. $this->auth = new BasicAuth($user, $pass);
  117. }
  118. else if ($type == 'WSSE') {
  119. require_once(dirname(__FILE__) . '/class.wsse.php');
  120. $this->auth = new WSSE($user, $pass);
  121. }
  122. else {
  123. $this->err_no = ATOMAPI_AUTHTYPE_INVALID;
  124. }
  125. }
  126. /**
  127. * @return String
  128. * @desc Returns the current authentication model (Basic or WSSE)
  129. */
  130. function get_authtype() {
  131. return $this->authtype;
  132. }
  133. /**
  134. * @return Boolean
  135. * @desc Verifies authentication details by attempting to access the endpoint. If successful, initiates the list of available feeds and returns true, otherwise returns false.
  136. */
  137. function verify_auth() {
  138. // Test authentication by accessing the endpoint with the auth object
  139. $ar = new AtomRequest('GET', $this->get_endpoint(), $this->auth, '');
  140. $response = $ar->exec();
  141. // Looks ok, return the Object
  142. if ($response == 200) {
  143. $this->get_feeds($ar->get_response());
  144. return true;
  145. }
  146. // Not a 200 Ok response - authetication failed, or endpoint incorrect
  147. else {
  148. $this->err_no = ATOMAPI_AUTHENTICATION_FAILED;
  149. return false;
  150. }
  151. }
  152. /**
  153. * @return AuthenticationObject
  154. * @desc Returns an authentication object (either WSSE or Basic)
  155. */
  156. function get_auth() {
  157. return $this->auth;
  158. }
  159. /**
  160. * @return Array/String
  161. * @desc Returns an array containing the details of the feeds listed at the endpoint. On failure, returns the HTTPCode as a string instead
  162. */
  163. function get_feeds($xml = false) {
  164. // Feeds already fetched? Then just return the array again
  165. if (is_array($this->feeds)) {
  166. return $this->feeds;
  167. }
  168. // First time the feeds are requested, so get the endpoint and build out the array
  169. else {
  170. if ($xml !== false) {
  171. $feeds_raw = $xml;
  172. }
  173. else {
  174. // Create an AtomRequest pointing to the AtomAPI endpoint (where we get a list of available feeds)
  175. $ar = new AtomRequest('GET', $this->endpoint, $this->auth, '');
  176. $code = $ar->exec();
  177. if ($code) {
  178. $feeds_raw = $ar->get_response();
  179. }
  180. else {
  181. $feeds_raw = false;
  182. }
  183. }
  184. // Request was successful
  185. if ($feeds_raw) {
  186. // Get the body of the response and parse out all <link>s
  187. preg_match_all('/(<link[^>]+rel="service.(feed|post)"[^>]*\/>)/Ui', $feeds_raw, $matches);
  188. if (strlen($matches[0][0])) {
  189. $feeds = array();
  190. // Build an array containing the details of all located <links>
  191. // <link>s are currently "paired" according to their URLs, so that the following is built;
  192. // $feeds = array('title'=>$title, 'service.feed'=>$FeedURI, 'service.edit'=>$EditURI);
  193. foreach ($matches[1] as $l=>$link) {
  194. preg_match('/href="([^"]+)"/i', $link, $href);
  195. preg_match('/title="([^"]+)"/i', $link, $title);
  196. foreach ($feeds as $f=>$feed) {
  197. if ($feed['service.post'] == $href[1] || $feed['service.feed'] == $href[1]) {
  198. $feeds[$f]['service.' . $matches[2][$l]] = $href[1];
  199. $feeds[$f]['title'] = $title[1];
  200. continue 2;
  201. }
  202. }
  203. $feeds[] = array('service.' . $matches[2][$l]=>$href[1], 'title'=>$title[1]);
  204. }
  205. $this->feeds = $feeds;
  206. return $feeds;
  207. }
  208. // No <link>s found - abort and return FALSE
  209. else {
  210. $this->err_no = ATOMAPI_NO_FEEDS;
  211. return false;
  212. }
  213. }
  214. // Request failed
  215. else {
  216. $this->err_no = ATOMAPI_NO_XML;
  217. return $code;
  218. }
  219. }
  220. }
  221. /**
  222. * @return AtomFeed
  223. * @param Int $id
  224. * @desc Creates (if required) and returns an AtomFeed object, based on an $id for the feeds array (pulled from endpoint)
  225. */
  226. function get_feed($id) {
  227. // Build the feeds array if it's not already initiated
  228. if (!sizeof($this->feeds)) {
  229. $this->get_feeds();
  230. }
  231. // And create this AtomFeed if it's not there
  232. if (!is_object($this->feed_objs[$id])) {
  233. $this->feed_objs[$id] = new AtomFeed($this->feeds[$id]['service.feed'], $this->get_auth());
  234. }
  235. // Return false if there's still no object
  236. if (!is_object($this->feed_objs[$id])) {
  237. return false;
  238. }
  239. // Return the requested AtomFeed
  240. else {
  241. return $this->feed_objs[$id];
  242. }
  243. }
  244. /**
  245. * @return Array/String
  246. * @param Int $id
  247. * @desc Creates an AtomFeed object for the details specified in $id, and gets the entries available. Stores the object internally for later
  248. */
  249. function get_entries($id) {
  250. // If the AtomFeed where entries are requested from doesn't exist, create it first
  251. if (!is_object($this->feed_objs[$id])) {
  252. $this->feed_objs[$id] = new AtomFeed($this->feeds[$id]['service.feed'], $this->auth);
  253. }
  254. // Return false if there's still no object
  255. if (!is_object($this->feed_objs[$id])) {
  256. return false;
  257. }
  258. // Request all entries available from this AtomFeed and return whatever comes back
  259. else {
  260. $entries = $this->feed_objs[$id]->get_entries();
  261. return $entries;
  262. }
  263. }
  264. /**
  265. * @return Int/FALSE
  266. * @desc Returns the last error registered in this class, or FALSE if none
  267. */
  268. function error() {
  269. if (isset($this->err_no) && is_int($this->err_no)) {
  270. return $this->err_no;
  271. }
  272. else {
  273. return false;
  274. }
  275. }
  276. }
  277.  
  278.  
  279.  
  280. class AtomFeed {
  281. var $endpoint;
  282. var $auth;
  283. var $title = array();
  284. var $author = array();
  285. var $version;
  286. var $links = array();
  287. var $tagline = array();
  288. var $id;
  289. var $generator = array();
  290. var $info = array();
  291. var $modified;
  292. var $entries = array();
  293. var $err_no;
  294. /**
  295. * @return AtomFeed
  296. * @param String $endpoint
  297. * @param AuthObj $auth
  298. * @param String $xml
  299. * @desc Creates an AtomFeed object, based on the details specified. If $xml is provided, then it is parsed to populate the object, otherwise the endpoint is accessed and it is populated from the response XML. If all values are false or omitted, then an empty AtomFeed is created, and awaits the use of set_*() functions to set it up manually.
  300. */
  301. function AtomFeed($endpoint = false, $auth = false, $xml = false) {
  302. // If they are set, then store the endpoint and auth object
  303. if ($endpoint && $auth) {
  304. $this->set_endpoint($endpoint);
  305. $this->set_auth($auth);
  306. }
  307. // If the object was created with XML, populate it with parsed values
  308. if ($xml !== false) {
  309. $this->from_xml($xml);
  310. }
  311. // No XML? If there's an endpoint and auth object, then get some XML to populate with
  312. else if ($endpoint && $auth) {
  313. $res = $this->init();
  314. // >= 300 is not a good http status code to get back
  315. if ($res >= 300) {
  316. return false;
  317. }
  318. }
  319. else {
  320. $this->err_no = ATOMAPI_FEED_INIT_FAILED;
  321. return false;
  322. }
  323. }
  324. /**
  325. * @return void
  326. * @param AuthObj $auth
  327. * @desc Sets the authentication object to use for this AtomFeed
  328. */
  329. function set_auth($auth) {
  330. if (is_object($auth)) {
  331. $this->auth = $auth;
  332. }
  333. else {
  334. $this->err_no = ATOMAPI_AUTHTYPE_INVALID;
  335. }
  336. }
  337. /**
  338. * @return AuthObj/FALSE
  339. * @desc Returns the currently set authentication object for this AtomFeed, or FALSE if not set
  340. */
  341. function get_auth() {
  342. if (is_object($this->auth)) {
  343. return $this->auth;
  344. }
  345. else {
  346. return false;
  347. }
  348. }
  349. /**
  350. * @return void
  351. * @param String $uri
  352. * @desc Set the endpoint for accessing this AtomFeed. Must be a fully-qualified URI starting with 'http'
  353. */
  354. function set_endpoint($uri) {
  355. if (substr($uri, 0, 4) == 'http') {
  356. $this->endpoint = $uri;
  357. }
  358. else {
  359. $this->err_no = ATOMAPI_ENDPOINT_INVALID;
  360. }
  361. }
  362. /**
  363. * @return String/FALSE
  364. * @desc Returns the endpoint for this AtomFeed if specified, or FALSE if not
  365. */
  366. function get_endpoint() {
  367. if (isset($this->endpoint) && strlen($this->endpoint)) {
  368. return $this->endpoint;
  369. }
  370. else {
  371. return false;
  372. }
  373. }
  374. /**
  375. * @return void
  376. * @param String $v
  377. * @desc Set the version number for this AtomFeed (goes in the <feed> element)
  378. */
  379. function set_version($v) {
  380. $this->version = $v;
  381. }
  382. /**
  383. * @return String
  384. * @desc Returns the version number specified for this AtomFeed in the <feed> element
  385. */
  386. function get_version() {
  387. if (isset($this->version)) {
  388. return $this->version;
  389. }
  390. else {
  391. return false;
  392. }
  393. }
  394. /**
  395. * @return void
  396. * @param String $i
  397. * @desc Sets the <id> element contents for the AtomFeed.
  398. */
  399. function set_id($i) {
  400. $this->id = $i;
  401. }
  402. /**
  403. * @return String
  404. * @desc Returns the contents of the <id> element for this AtomFeed
  405. */
  406. function get_id() {
  407. if (isset($this->id)) {
  408. return $this->id;
  409. }
  410. else {
  411. return false;
  412. }
  413. }
  414. /**
  415. * @return void
  416. * @param Array/String $title
  417. * @desc Sets the title for this AtomFeed.
  418. */
  419. function set_title($title) {
  420. if (is_array($title)) {
  421. foreach ($title as $key=>$val) {
  422. if (strlen($key) && strlen($val)) {
  423. $this->title[$key] = $val;
  424. }
  425. }
  426. }
  427. else if (is_string($title)) {
  428. $this->title['title'] = $title;
  429. }
  430. }
  431. /**
  432. * @return Array/String/FALSE
  433. * @param String $elem
  434. * @desc Returns either a specific element of the title, or the entire array of data if none is specified.
  435. */
  436. function get_title($elem = false) {
  437. if ($elem === false) {
  438. return $this->title;
  439. }
  440. else {
  441. if (in_array($elem, array_keys($this->title))) {
  442. return $this->title[$elem];
  443. }
  444. else {
  445. return false;
  446. }
  447. }
  448. }
  449. /**
  450. * @return void
  451. * @param Array/String $tagline
  452. * @desc Sets the details of the tagline for this AtomFeed
  453. */
  454. function set_tagline($tagline) {
  455. if (is_array($tagline)) {
  456. foreach ($tagline as $key=>$val) {
  457. $this->tagline[$key] = $val;
  458. }
  459. }
  460. else if (is_string($tagline)) {
  461. $this->tagline['tagline'] = $tagline;
  462. }
  463. }
  464. /**
  465. * @return Array/String/FALSE
  466. * @param String $elem
  467. * @desc Returns either a specific element of the tagline, or the entire array of data if none is specified.
  468. */
  469. function get_tagline($elem = false) {
  470. if ($elem === false) {
  471. return $this->tagline;
  472. }
  473. else {
  474. if (in_array($elem, array_keys($this->tagline))) {
  475. return $this->tagline[$elem];
  476. }
  477. else {
  478. return false;
  479. }
  480. }
  481. }
  482. /**
  483. * @return void
  484. * @param Array $gen
  485. * @desc Sets the details of the generator for this AtomFeed.
  486. */
  487. function set_generator($gen) {
  488. if (is_array($gen)) {
  489. foreach ($gen as $key=>$val) {
  490. $this->generator[$key] = $val;
  491. }
  492. }
  493. }
  494. /**
  495. * @return void
  496. * @param String $date
  497. * @desc Set the modified date for this feed
  498. */
  499. function set_modified($date) {
  500. if (preg_match('/(\d{4})-(\d{2})-(\d{2}).(\d{2}):(\d{2}):(\d{2})-(\d{2}):(\d{2})/', $date, $parts) || preg_match('/(\d{4})-(\d{2})-(\d{2}).(\d{2}):(\d{2}):(\d{2})Z/', $date, $parts)) {
  501. $this->modified = $date;
  502. }
  503. }
  504. /**
  505. * @return String/FALSE
  506. * @desc Get the modified date for this feed, or FALSE if it's not set
  507. */
  508. function get_modified() {
  509. if (isset($this->modified) && strlen($this->modified)) {
  510. return $this->modified;
  511. }
  512. else {
  513. return false;
  514. }
  515. }
  516. /**
  517. * @return void
  518. * @param Array/String $info
  519. * @desc Set the info element details. If a string is passed in, then defaults to the info contents
  520. */
  521. function set_info($info) {
  522. if (is_array($info)) {
  523. foreach ($info as $key=>$val) {
  524. $this->info[$key] = $val;
  525. }
  526. }
  527. else {
  528. $this->info['info'] = $info;
  529. }
  530. }
  531. /**
  532. * @return Array/String/FALSE
  533. * @desc Returns either the requested individual attribute of the info element, the entire array, or FALSE if it's not set.
  534. */
  535. function get_info($elem = false) {
  536. if ($elem === false) {
  537. return $this->info;
  538. }
  539. else {
  540. if (in_array($elem, array_keys($this->info))) {
  541. return $this->info[$elem];
  542. }
  543. else {
  544. return false;
  545. }
  546. }
  547. }
  548. /**
  549. * @return Array/String/FALSE
  550. * @param String $elem
  551. * @desc Returns either a specific element of the generator, or the entire array of data if none is specified.
  552. */
  553. function get_generator($elem = false) {
  554. if ($elem === false) {
  555. return $this->generator;
  556. }
  557. else {
  558. if (in_array($elem, array_keys($this->generator))) {
  559. return $this->generator[$elem];
  560. }
  561. else {
  562. return false;
  563. }
  564. }
  565. }
  566. /**
  567. * @return void
  568. * @param String $href
  569. * @param String $rel
  570. * @param String $title
  571. * @param String $type
  572. * @desc Adds a link to the links array with the details as per the associative array passed in. Requires href, rel, title and type
  573. */
  574. function add_link($href, $rel, $title = '', $type) {
  575. if (strlen($href) && strlen($rel) && strlen($type)) {
  576. $this->links[] = array('href'=>$href, 'rel'=>$rel, 'title'=>$title, 'type'=>$type);
  577. }
  578. }
  579. /**
  580. * @return Array
  581. * @param String $key
  582. * @param String $val
  583. * @desc Filters the <link>s of this AtomFeed for ones where the $key matches the $val and returns an array of them, otherwise returns all links
  584. */
  585. function get_links($key = false, $val = false) {
  586. // If key and val are specified, then filter the array for entries where the specified key == the value
  587. if ($key !== false && $val !== false) {
  588. $out = array();
  589. foreach ($this->links as $link) {
  590. if ($link[$key] == $val) {
  591. $out[] = $link;
  592. }
  593. }
  594. }
  595. else {
  596. $out = $this->links;
  597. }
  598. return $out;
  599. }
  600. /**
  601. * @return Array/FALSE
  602. * @desc Returns an array containing AtomEntries for each entry in this AtomFeed, or FALSE if none are set
  603. */
  604. function get_entries() {
  605. if (sizeof($this->entries)) {
  606. return $this->entries;
  607. }
  608. else {
  609. return false;
  610. }
  611. }
  612. /**
  613. * @return void
  614. * @param AtomEntry $entry
  615. * @desc Add an AtomEntry object to the array of entries that make up this AtomFeed
  616. */
  617. function add_entry($entry) {
  618. if (is_object($entry)) {
  619. $this->entries[] = $entry;
  620. }
  621. }
  622. /**
  623. * @return TRUE/Int on error
  624. * @desc Initiates the AtomFeed object from a URI by loading the data, then parsing it as XML. Returns an HTTP response code on error, or TRUE if successful.
  625. */
  626. function init() {
  627. $ar = new AtomRequest('GET', $this->get_endpoint(), $this->get_auth());
  628. $code = $ar->exec();
  629. // Successfully retrieved feed, now process it out
  630. if ($code == 200) {
  631. $this->from_xml($ar->get_response());
  632. return true;
  633. }
  634. // Not a clean result, return the error
  635. else {
  636. $this->err_no = ATOMAPI_FEED_INIT_FAILED;
  637. return $code;
  638. }
  639. }
  640. /**
  641. * @return Array/FALSE
  642. * @param String $str
  643. * @desc Parses an XML/HTML string and returns an associative array containing key/value pairs
  644. */
  645. function extract_attribs($str) {
  646. $out = array();
  647. if (preg_match_all('/([^ =]+)="([^"]*)"/si', $str, $attribs)) {
  648. foreach ($attribs[1] as $c=>$key) {
  649. $out[$key] = $attribs[2][$c];
  650. }
  651. }
  652. return $out;
  653. }
  654. /**
  655. * @return void
  656. * @param String $xml
  657. * @desc Populates the variables of the AtomFeed, based on a complete XML representation of it.
  658. */
  659. function from_xml($xml) {
  660. $orig_xml = $xml;
  661. // Strip down the XML to just the part we want to work with
  662. if (preg_match('/(<feed.*)<entry/sUi', $xml, $feed_xml)) {
  663. $xml = $feed_xml[1];
  664. }
  665. // ATOM FEED VERSION
  666. if (preg_match('/<feed[^>]+version="([^"]*)"/is', $xml, $ver)) {
  667. $this->set_version($ver[1]);
  668. }
  669. // TITLE
  670. if (preg_match_all('/<title([^>]*)>(.*)<\/title>/sUi', $xml, $title)) {
  671. $title_attribs = $this->extract_attribs($title[1][0]);
  672. $title = array('title'=>$title[2][0]);
  673. $title = array_merge_recursive($title, $title_attribs);
  674. $this->set_title($title);
  675. }
  676. // TAGLINE
  677. if (preg_match_all('/<tagline([^>]*)>(.*)<\/tagline>/sUi', $xml, $tagline)) {
  678. $tagline_attribs = $this->extract_attribs($tagline[1][0]);
  679. $tagline = array('tagline'=>$tagline[2][0]);
  680. $tagline = array_merge_recursive($tagline, $tagline_attribs);
  681. $this->set_tagline($tagline);
  682. }
  683. // ID
  684. if (preg_match('/<id>([^<]*)<\/id>/is', $xml, $id)) {
  685. $this->set_id($id[1]);
  686. }
  687. // INFO
  688. if (preg_match('/<info([^>]+)>(.*)<\/info>/is', $xml, $info)) {
  689. $info_attribs = $this->extract_attribs($info[1]);
  690. $info = array('info'=>$info[2]);
  691. $info = array_merge_recursive($info, $info_attribs);
  692. $this->set_info($info);
  693. }
  694. // MODIFIED
  695. if (preg_match('/<modified>([^<]*)<\/modified>/is', $xml, $modified)) {
  696. $this->set_modified($modified[1]);
  697. }
  698. // GENERATOR
  699. if (preg_match_all('/<generator([^>]*)>(.*)<\/generator>/sUi', $xml, $generator)) {
  700. $generator_attribs = $this->extract_attribs($generator[1][0]);
  701. $generator = array('generator'=>$generator[2][0]);
  702. $generator = array_merge_recursive($generator, $generator_attribs);
  703. $this->set_generator($generator);
  704. }
  705. // LINKS
  706. if (preg_match_all('/<link([^>]+)>/Ui', $xml, $links)) {
  707. foreach ($links[1] as $link) {
  708. $link = $this->extract_attribs($link);
  709. $this->add_link($link['href'], $link['rel'], $link['title'], $link['type']);
  710. }
  711. }
  712. // Handle all of the entries, creating AtomEntry objects and linking them
  713. preg_match_all('/(<entry[^>]*>.*<\/entry>)/sUi', $orig_xml, $entries_raw);
  714. if (strlen($entries_raw[0][0])) {
  715. foreach ($entries_raw[1] as $e=>$entry) {
  716. $ae = new AtomEntry();
  717. $ae->from_xml($entry);
  718. if ($ae) {
  719. $this->add_entry($ae);
  720. }
  721. }
  722. }
  723. }
  724. /**
  725. * @return String
  726. * @desc Returns an XML/String representation of the entire AtomFeed, including header values and all AtomEntries found in $this->entries.
  727. */
  728. function to_xml() {
  729. $xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n\n";
  730. $xml .= '<feed';
  731. // VERSION
  732. $ver = $this->get_version();
  733. if ($ver) {
  734. $xml .= ' version="' . $ver . '"';
  735. }
  736. $xml .= ' xmlns="http://purl.org/atom/ns#">' . "\n";
  737. // LINKS
  738. $links = $this->get_links();
  739. if (sizeof($links)) {
  740. foreach ($links as $link) {
  741. $xml .= '<link';
  742. foreach ($link as $attrib=>$val) {
  743. if (strlen($attrib) && strlen($val)) {
  744. $xml .= ' ' . $attrib . '="' . utf8_encode($val) . '"';
  745. }
  746. }
  747. $xml .= '/>' . "\n";
  748. }
  749. }
  750. // TITLE
  751. $title = $this->get_title();
  752. if (sizeof($title)) {
  753. $xml .= '<title';
  754. foreach ($title as $key=>$val) {
  755. if ($key != 'title') {
  756. $xml .= ' ' . $key . '="' . $val . '"';
  757. }
  758. }
  759. $xml .= '>' . utf8_encode($title['title']) . '</title>' . "\n";
  760. }
  761. // TAGLINE
  762. $tag = $this->get_tagline();
  763. if (sizeof($tag)) {
  764. $xml .= '<tagline';
  765. foreach ($tag as $key=>$val) {
  766. if ($key != 'tagline') {
  767. $xml .= ' ' . $key . '="' . $val . '"';
  768. }
  769. }
  770. $xml .= '>' . utf8_encode($tag['tagline']) . '</tagline>' . "\n";
  771. }
  772. // ID
  773. $id = $this->get_id();
  774. if ($id) {
  775. $xml .= '<id>' . $id . '</id>' . "\n";
  776. }
  777. // MODIFIED
  778. $mod = $this->get_modified();
  779. if ($mod) {
  780. $xml .= '<modified>' . $mod . '</modified>' . "\n";
  781. }
  782. // GENERATOR
  783. $gen = $this->get_generator();
  784. if (is_array($gen) && sizeof($gen)) {
  785. $xml .= '<generator url="' . $gen['url'] . '" version="' . $gen['version'] . '">' . $gen['generator'] . '</generator>' . "\n";
  786. }
  787. // INFO
  788. $info = $this->get_info();
  789. if (sizeof($info)) {
  790. $xml .= '<info';
  791. foreach ($info as $key=>$val) {
  792. if ($key != 'info') {
  793. $xml .= ' ' . $key . '="' . $val . '"';
  794. }
  795. }
  796. $xml .= '>' . utf8_encode($info['info']) . '</info>' . "\n";
  797. }
  798. // ENTRIES
  799. $entries = $this->get_entries();
  800. if ($entries) {
  801. foreach ($entries as $entry) {
  802. $xml .= $entry->to_xml('FEED');
  803. }
  804. }
  805. $xml .= '</feed>';
  806. return $xml;
  807. }
  808. /**
  809. * @return Int/FALSE
  810. * @desc Returns the last error registered in this class, or FALSE if none
  811. */
  812. function error() {
  813. if (isset($this->err_no) && is_int($this->err_no)) {
  814. return $this->err_no;
  815. }
  816. else {
  817. return false;
  818. }
  819. }
  820. }
  821.  
  822.  
  823.  
  824. class AtomEntry {
  825. var $links = array();
  826. var $title = array();
  827. var $content = array();
  828. var $author = array();
  829. var $generator = array();
  830. var $issued;
  831. var $modified;
  832. var $created;
  833. var $id;
  834. var $err_no;
  835. /**
  836. * @return AtomEntry
  837. * @param Array $title
  838. * @param Array $content
  839. * @param Array $author
  840. * @param String $issued
  841. * @param String $modified
  842. * @param String $created
  843. * @desc Creates an AtomEntry, with optional initial values.
  844. */
  845. function AtomEntry($title = array(), $content = array()) {
  846. $this->set_title($title);
  847. $this->set_content($content);
  848. // Default timezone is that of the current server (for dates)
  849. $this->tz = date('O');
  850. }
  851. /**
  852. * @return void
  853. * @param Array $title
  854. * @desc Sets the title details for the Entry, including some defaults if ommitted. FORMAT: array('title'=>$title);
  855. */
  856. function set_title($title) {
  857. if (is_array($title)) {
  858. foreach ($title as $key=>$val) {
  859. if (strlen($key) && strlen($val)) {
  860. $this->title[$key] = $val;
  861. }
  862. }
  863. }
  864. else if (is_string($title)) {
  865. $this->title['title'] = $title;
  866. $this->title['mode'] = 'escaped';
  867. }
  868. }
  869. /**
  870. * @return String/Array/FALSE
  871. * @param String $elem
  872. * @desc Returns either the requested value, or all details of the $title
  873. */
  874. function get_title($elem = false) {
  875. if ($elem === false) {
  876. return $this->title;
  877. }
  878. else {
  879. if (in_array($elem, array_keys($this->title))) {
  880. return $this->title[$elem];
  881. }
  882. else {
  883. return false;
  884. }
  885. }
  886. }
  887. /**
  888. * @return void
  889. * @param Array $content
  890. * @desc Sets the content details for the Entry, including some defaults if ommitted. FORMAT: array('content'=>$content); Also removes default <DIV> from Blogger entries to avoid PUT problems
  891. */
  892. function set_content($content) {
  893. if (is_array($content)) {
  894. foreach ($content as $key=>$val) {
  895. $this->content[$key] = $val;
  896. }
  897. }
  898. else if (is_string($content)) {
  899. $this->content['content'] = $content;
  900. $this->content['mode'] = 'escaped';
  901. }
  902. }
  903. /**
  904. * @return Array/String/FALSE
  905. * @param String $elem
  906. * @desc Returns the contents of this entry - including attributes of the content element
  907. */
  908. function get_content($elem = false) {
  909. if ($elem === false) {
  910. return $this->content;
  911. }
  912. else {
  913. if (in_array($elem, array_keys($this->content))) {
  914. return $this->content[$elem];
  915. }
  916. else {
  917. return false;
  918. }
  919. }
  920. }
  921. /**
  922. * @return void
  923. * @param Array $author
  924. * @desc Set all details relating to the author (name, email, url)
  925. */
  926. function set_author($author) {
  927. if (is_array($author)) {
  928. foreach ($author as $key=>$val) {
  929. $this->author[$key] = $val;
  930. }
  931. }
  932. else if (is_string($author)) {
  933. $this->author['name'] = $author;
  934. }
  935. }
  936. /**
  937. * @return Array/String/FALSE
  938. * @param String $elem
  939. * @desc Returns author details - either item requested, or all.
  940. */
  941. function get_author($elem = false) {
  942. if ($elem === false) {
  943. return $this->author;
  944. }
  945. else {
  946. if (in_array($elem, array_keys($this->author))) {
  947. return $this->author[$elem];
  948. }
  949. else {
  950. return false;
  951. }
  952. }
  953. }
  954. /**
  955. * @return void
  956. * @param String $date
  957. * @desc Set the <issued> date, after sanitization
  958. */
  959. function set_issued($date) {
  960. $this->issued = $this->sanitize_date($date);
  961. }
  962. /**
  963. * @return String
  964. * @desc Returns the <issued> date for the entry
  965. */
  966. function get_issued() {
  967. if (isset($this->issued)) {
  968. return $this->issued;
  969. }
  970. else {
  971. return false;
  972. }
  973. }
  974. /**
  975. * @return void
  976. * @param String $date
  977. * @desc Set the <modified> date, after sanitization
  978. */
  979. function set_modified($date) {
  980. $this->modified = $this->sanitize_date($date);
  981. }
  982. /**
  983. * @return String/FALSE
  984. * @desc Returns the <modified> date for the entry
  985. */
  986. function get_modified() {
  987. if (isset($this->modified)) {
  988. return $this->modified;
  989. }
  990. else {
  991. return false;
  992. }
  993. }
  994. /**
  995. * @return void
  996. * @param String $date
  997. * @desc Set the <created> date, after sanitization
  998. */
  999. function set_created($date) {
  1000. $this->created = $this->sanitize_date($date);
  1001. }
  1002. /**
  1003. * @return String/FALSE
  1004. * @desc Returns the <created> date for the entry
  1005. */
  1006. function get_created() {
  1007. if (isset($this->created)) {
  1008. return $this->created;
  1009. }
  1010. else {
  1011. return false;
  1012. }
  1013. }
  1014. /**
  1015. * @return void
  1016. * @param String $id
  1017. * @desc Set the unique <id> for the Entry
  1018. */
  1019. function set_id($id) {
  1020. $this->id = $id;
  1021. }
  1022. /**
  1023. * @return String/FALSE
  1024. * @desc Returns the unique <id> for this Entry
  1025. */
  1026. function get_id() {
  1027. if (isset($this->id)) {
  1028. return $this->id;
  1029. }
  1030. else {
  1031. return false;
  1032. }
  1033. }
  1034. /**
  1035. * @return void
  1036. * @param String $href
  1037. * @param String $rel
  1038. * @param String $title
  1039. * @param String $type
  1040. * @desc Adds a <link> to the array for this Entry. href, type, title and rel are all required
  1041. */
  1042. function add_link($href, $rel, $title, $type) {
  1043. if (strlen($href) && strlen($rel) && strlen($type)) {
  1044. $this->links[] = array('href'=>$href, 'rel'=>$rel, 'title'=>$title, 'type'=>$type);
  1045. }
  1046. }
  1047. /**
  1048. * @return Array
  1049. * @param String $key
  1050. * @param String $val
  1051. * @desc Returns the links where $key matches $val if specified, or all links if both ommitted
  1052. */
  1053. function get_links($key = false, $val = false) {
  1054. // If key and val are specified, then filter the array for entries where the specified key == the value
  1055. if ($key !== false && $val !== false) {
  1056. $out = array();
  1057. foreach ($this->links as $link) {
  1058. if ($link[$key] == $val) {
  1059. $out[] = $link;
  1060. }
  1061. }
  1062. }
  1063. else {
  1064. $out = $this->links;
  1065. }
  1066. return $out;
  1067. }
  1068. function sanitize_date($date) {
  1069. if ($date == '' || $date === false) {
  1070. return false;
  1071. }
  1072. else if (!stristr($date, 'T') || !stristr($date, 'Z')) {
  1073. if (preg_match('/(\d{4})-(\d{2})-(\d{2}).(\d{2}):(\d{2}):(\d{2})-(\d{2}):(\d{2})/', $date, $parts)) {
  1074. return $date;
  1075. }
  1076. else if (preg_match('/(\d{4})-(\d{2})-(\d{2}).(\d{2}):(\d{2}):(\d{2})/', $date, $parts)) {
  1077. return $date;
  1078. }
  1079. return false;
  1080. }
  1081. else {
  1082. return $date;
  1083. }
  1084. }
  1085. function atom_date($date, $tz) {
  1086. if ($date == '' || $date === false) {
  1087. preg_match('/(\+|-)(\d{2}):(\d{2})/', $tz, $tz_parts);
  1088. return gmdate('Y-m-d\TH:i:s\Z', mktime(eval("date('H') " . $tz_parts[1] . " " . $tz_parts[2] . ";"), eval("date('i') " . $tz_parts[1] . " " . $tz_parts[3] . ";"), date('s'), date('m'), date('d'), date('Y')));
  1089. }
  1090. else {
  1091. return $date;
  1092. }
  1093. }
  1094. /**
  1095. * @return Array
  1096. * @param String $str
  1097. * @desc Parses an XML/HTML string and returns an associative array containing key/value pairs
  1098. */
  1099. function extract_attribs($str) {
  1100. $out = array();
  1101. if (preg_match_all('/([^ =]+)="([^"]*)"/si', $str, $attribs)) {
  1102. foreach ($attribs[1] as $c=>$key) {
  1103. $out[$key] = $attribs[2][$c];
  1104. }
  1105. }
  1106. return $out;
  1107. }
  1108. /**
  1109. * @return void
  1110. * @param String $xml
  1111. * @desc Builds out the details of the object by parsing an XML <entry>
  1112. */
  1113. function from_xml($xml) {
  1114. // Parse an XML <entry> into its elements and then set them to this Object
  1115. // LINKS
  1116. if (preg_match_all('/<link([^>]+)>/Ui', $xml, $links)) {
  1117. foreach ($links[1] as $link) {
  1118. $link = $this->extract_attribs($link);
  1119. $this->add_link($link['href'], $link['rel'], $link['title'], $link['type']);
  1120. }
  1121. }
  1122. // AUTHOR----------------------------------------------------------------------------------------------*
  1123. // Needs to handle the other elements properly - but need a sample to work from!
  1124. if (preg_match('/<author>\s*(<([^>]+)>(.*)<\/\2>)*\s*<\/author>/sUi', $xml, $author)) {
  1125. $this->set_author(array($author[2]=>$author[3]));
  1126. }
  1127. // DATES
  1128. if (preg_match('/<issued>([^>]*)<\/issued>/i', $xml, $date)) {
  1129. $this->set_issued($date[1]);
  1130. }
  1131. if (preg_match('/<modified>([^>]*)<\/modified>/i', $xml, $date)) {
  1132. $this->set_modified($date[1]);
  1133. }
  1134. if (preg_match('/<created>([^>]*)<\/created>/i', $xml, $date)) {
  1135. $this->set_created($date[1]);
  1136. }
  1137. // ID
  1138. if (preg_match('/<id>([^>]*)<\/id>/i', $xml, $id)) {
  1139. $this->set_id($id[1]);
  1140. }
  1141. // TITLE
  1142. if (preg_match_all('/<title([^>]*)>(.*)<\/title>/sUi', $xml, $title)) {
  1143. $title_attribs = $this->extract_attribs($title[1][0]);
  1144. $title = array('title'=>$title[2][0]);
  1145. $title = array_merge_recursive($title, $title_attribs);
  1146. $this->set_title($title);
  1147. }
  1148. // CONTENT
  1149. if (preg_match_all('/<content([^>]*)>(.*)<\/content>/sUi', $xml, $content)) {
  1150. $content_attribs = $this->extract_attribs($content[1][0]);
  1151. $content = array('content'=>$content[2][0]);
  1152. $content = array_merge_recursive($content, $content_attribs);
  1153. $this->set_content($content);
  1154. }
  1155. }
  1156. /**
  1157. * @return String
  1158. * @param String $purpose
  1159. * @desc Creates an XML representation of this Entry. $purpose is [PUT|POST|FEED] and defines what you're going to do with this XML. $purpose modifies the elements included according to the Atom spec.
  1160. */
  1161. function to_xml($purpose = 'POST') {
  1162. $xml = '';
  1163. // XML prolog if PUT or POST
  1164. if ($purpose == 'PUT' || $purpose == 'POST') {
  1165. $xml .= '<?xml version="1.0" encoding="utf-8"?>' . "\n";
  1166. }
  1167.  
  1168. // Start XML packet
  1169. $xml .= '<entry xmlns="http://purl.org/atom/ns#">' . "\n";
  1170. // GENERATOR
  1171. if ($purpose == 'PUT' || $purpose == 'POST') {
  1172. $xml .= '<generator version="0.1" url="http://www.dentedreality.com.au/phpatomapi/">Dented Reality PHP Atom API</generator>' . "\n";
  1173. }
  1174. // LINKS
  1175. $links = $this->get_links();
  1176. if (sizeof($links)) {
  1177. foreach ($links as $link) {
  1178. $xml .= '<link';
  1179. foreach ($link as $attrib=>$val) {
  1180. if (strlen($attrib) && strlen($val)) {
  1181. $xml .= ' ' . $attrib . '="' . utf8_encode($val) . '"';
  1182. }
  1183. }
  1184. $xml .= '/>' . "\n";
  1185. }
  1186. }
  1187. // AUTHOR
  1188. $author = $this->get_author();
  1189. if (sizeof($author)) {
  1190. $xml .= '<author>';
  1191. foreach ($author as $key=>$val) {
  1192. if (strlen($key) && strlen($val)) {
  1193. $xml .= '<' . $key .'>' . utf8_encode($val) . '</' . $key . '>' . "\n";
  1194. }
  1195. }
  1196. $xml .= '</author>' . "\n";
  1197. }
  1198. // DATES (issued, created, modified)
  1199. if (strlen($this->get_issued())) {
  1200. $xml .= '<issued>' . $this->get_issued() . '</issued>' . "\n";
  1201. }
  1202. // Modified and Id, only if not creating a POST entry
  1203. if ($purpose != 'POST' && $purpose != 'PUT') {
  1204. if (strlen($this->get_created())) {
  1205. $xml .= '<created>' . $this->get_created() . '</created>' . "\n";
  1206. }
  1207. if (strlen($this->get_modified())) {
  1208. $xml .= '<modified>' . $this->get_modified() . '</modified>' . "\n";
  1209. }
  1210. // ID element
  1211. $xml .= '<id>' . $this->id . '</id>' . "\n";
  1212. }
  1213. // TITLE
  1214. $title = $this->get_title();
  1215. if (is_array($title)) {
  1216. $xml .= '<title';
  1217. foreach ($title as $key=>$val) {
  1218. if ($key != 'title') {
  1219. $xml .= ' ' . $key . '="' . $val . '"';
  1220. }
  1221. }
  1222. $xml .= '>' . utf8_encode($title['title']) . '</title>' . "\n";
  1223. }
  1224. // CONTENT
  1225. $content = $this->get_content();
  1226. if (is_array($content)) {
  1227. $xml .= '<content';
  1228. foreach ($content as $key=>$val) {
  1229. if ($key != 'content') {
  1230. $xml .= ' ' . $key . '="' . $val . '"';
  1231. }
  1232. }
  1233. $xml .= '>' . utf8_encode($content['content']) . '</content>' . "\n";
  1234. }
  1235. $xml .= '</entry>' . "\n\n";
  1236. return $xml;
  1237. }
  1238. /**
  1239. * @return Int/FALSE
  1240. * @desc Returns the last error registered in this class, or FALSE if none
  1241. */
  1242. function error() {
  1243. if (isset($this->err_no) && is_int($this->err_no)) {
  1244. return $this->err_no;
  1245. }
  1246. else {
  1247. return false;
  1248. }
  1249. }
  1250. }
  1251.  
  1252.  
  1253.  
  1254. class AtomRequest {
  1255. var $method;
  1256. var $uri;
  1257. var $auth;
  1258. var $payload;
  1259. var $response;
  1260. var $httpcode;
  1261. var $err_no;
  1262. /**
  1263. * @return AtomRequest
  1264. * @param String $method
  1265. * @param String $uri
  1266. * @param AuthObject $auth
  1267. * @param String $payload
  1268. * @desc Creates an object with functions for performing standard Atom requests. $method should be [GET|PUT|POST|DELETE], $uri is the endpoint/uri to execute the request against, $auth is an authentication object (BasicAuth or WSSE) and $payload is the XML of the request, if required (POST|PUT)
  1269. */
  1270. function AtomRequest($method, $uri, $auth, $payload = false) {
  1271. $this->set_method($method);
  1272. $this->set_uri($uri);
  1273. $this->set_auth($auth);
  1274. $this->set_payload($payload);
  1275. if ($this->error()) {
  1276. return false;
  1277. }
  1278. }
  1279. /**
  1280. * @return void
  1281. * @param String $uri
  1282. * @desc Set the URI to execute this AtomRequest against. Should be a fully-qualified URL and start with 'http'
  1283. */
  1284. function set_uri($uri) {
  1285. if (substr($uri, 0, 4) == 'http') {
  1286. $this->uri = $uri;
  1287. }
  1288. else {
  1289. $this->err_no = ATOMAPI_ENDPOINT_INVALID;
  1290. }
  1291. }
  1292. /**
  1293. * @return String/FALSE on error
  1294. * @desc Returns the URI stored for this AtomRequest to operate against, or FALSE if not set yet
  1295. */
  1296. function get_uri() {
  1297. if (isset($this->uri) && strlen($this->uri)) {
  1298. return $this->uri;
  1299. }
  1300. else {
  1301. return false;
  1302. }
  1303. }
  1304. /**
  1305. * @return void
  1306. * @param AuthObj $auth
  1307. * @desc Set the authentication object to use for this AtomRequest
  1308. */
  1309. function set_auth($auth) {
  1310. if (is_object($auth)) {
  1311. $this->auth = $auth;
  1312. }
  1313. else {
  1314. $this->err_no = ATOMAPI_AUTHTYPE_INVALID;
  1315. }
  1316. }
  1317. /**
  1318. * @return void
  1319. * @param String $method
  1320. * @desc Sets the method of this AtomRequest. Allowed values are [GET|PUT|POST|DELETE]
  1321. */
  1322. function set_method($method) {
  1323. if (in_array($method, array('GET', 'PUT', 'POST', 'DELETE'))) {
  1324. $this->method = $method;
  1325. }
  1326. else {
  1327. $this->err_no = ATOMAPI_METHOD_INVALID;
  1328. }
  1329. }
  1330. /**
  1331. * @return String/FALSE on error
  1332. * @desc Returns the current $method set for this AtomRequest. Should be [GET|PUT|POST|DELETE]. Returns FALSE if it is unset.
  1333. */
  1334. function get_method() {
  1335. if (isset($this->method) && strlen($this->method)) {
  1336. return $this->method;
  1337. }
  1338. else {
  1339. return false;
  1340. }
  1341. }
  1342. /**
  1343. * @return void
  1344. * @param String $xml
  1345. * @desc Set the payload (body) of the AtomRequest. Should be an XML string, and is only required for POST and PUT operations
  1346. */
  1347. function set_payload($xml) {
  1348. if (is_string($xml)) {
  1349. $this->payload = $xml;
  1350. }
  1351. else {
  1352. $this->err_no = ATOMAPI_PAYLOAD_INVALID;
  1353. }
  1354. }
  1355. /**
  1356. * @return String/FALSE on error
  1357. * @desc Returns the current stored payload, which should be an XML package, or FALSE if it is not set yet.
  1358. */
  1359. function get_payload() {
  1360. if (isset($this->payload)) {
  1361. return $this->payload;
  1362. }
  1363. else {
  1364. return false;
  1365. }
  1366. }
  1367. /**
  1368. * @return Int/FALSE on error
  1369. * @desc Executes the AtomRequest on the URI specified in the object. Returns the HTTP response code, or FALSE on a serious error
  1370. */
  1371. function exec() {
  1372. // Confirm minimum requirements (method, uri)
  1373. if (!$this->get_uri() || !$this->get_method()) {
  1374. $this->err_no = ATOMAPI_REQUEST_INVALID;
  1375. return;
  1376. }
  1377. // Common cURL configuration directives
  1378. $ch = curl_init();
  1379. curl_setopt($ch, CURLOPT_URL, $this->get_uri());
  1380. curl_setopt($ch, CURLOPT_USERAGENT, "Dented Reality PHP Atom API Library v0.1");
  1381. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // Don't stress about SSL validity
  1382. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return the response, don't output it
  1383. // Handle configuration of specific options for certain request types
  1384. switch ($this->get_method()) {
  1385. case 'POST' :
  1386. // Authentication header and content-type
  1387. $headers = $this->auth->get_header(true);
  1388. $headers[] = 'Content-type: application/xml';
  1389. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  1390. // Configuring post contents (should be an XML payload)
  1391. curl_setopt($ch, CURLOPT_POST, 1);
  1392. curl_setopt($ch, CURLOPT_POSTFIELDSIZE, strlen($this->get_payload()));
  1393. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->get_payload());
  1394. break;
  1395. case 'PUT' :
  1396. // PUT requires the payload to be written to file, and passed as a file pointer
  1397. $put = tmpfile();
  1398. fputs($put, $this->get_payload());
  1399. rewind($put);
  1400. // Authentication headers and content-type
  1401. $headers = $this->auth->get_header(true);
  1402. $headers[] = 'Content-type: application/xml';
  1403. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  1404. // Performing a PUT operation, requires file pointer and size of payload
  1405. curl_setopt($ch, CURLOPT_PUT, 1);
  1406. curl_setopt($ch, CURLOPT_INFILE, $put);
  1407. curl_setopt($ch, CURLOPT_INFILESIZE, strlen($this->get_payload()));
  1408. break;
  1409. case 'DELETE' :
  1410. // Simple DELETE request (authenticated)
  1411. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
  1412. curl_setopt($ch, CURLOPT_HTTPHEADER, $this->auth->get_header(true));
  1413. break;
  1414. case 'GET' :
  1415. default :
  1416. // Straight GET, with authentication headers
  1417. curl_setopt($ch, CURLOPT_HTTPHEADER, $this->auth->get_header(true));
  1418. }
  1419. // Execute cURL session and handle results
  1420. $this->response = curl_exec($ch);
  1421. if (curl_errno($ch)) {
  1422. $this->err_no = ATOMAPI_CURL_ERROR;
  1423. curl_close($ch);
  1424. return;
  1425. }
  1426. else {
  1427. // Set the HTTPcode of the response into this object, then return it
  1428. $this->set_httpcode(curl_getinfo($ch, CURLINFO_HTTP_CODE));
  1429. curl_close($ch);
  1430. return $this->get_httpcode();
  1431. }
  1432. }
  1433. /**
  1434. * @return String/FALSE on error
  1435. * @desc Returns the response content from the exec()'d AtomRequest, or FALSE if not set yet
  1436. */
  1437. function get_response() {
  1438. if (isset($this->response)) {
  1439. return $this->response;
  1440. }
  1441. else {
  1442. return false;
  1443. }
  1444. }
  1445. /**
  1446. * @return void
  1447. * @param Int $code
  1448. * @desc Internal function, used to update the http status code returned when the AtomRequest is exec()'d
  1449. */
  1450. function set_httpcode($code) {
  1451. if (strlen($code) && is_int($code)) {
  1452. $this->httpcode = $code;
  1453. }
  1454. else {
  1455. $this->httpcode = false;
  1456. }
  1457. }
  1458. /**
  1459. * @return Int/FALSE on error
  1460. * @desc Returns the last stored http status code for this AtomRequest
  1461. */
  1462. function get_httpcode() {
  1463. if (isset($this->httpcode) && strlen($this->httpcode)) {
  1464. return $this->httpcode;
  1465. }
  1466. else {
  1467. return false;
  1468. }
  1469. }
  1470. /**
  1471. * @return Int/FALSE
  1472. * @desc Returns the last error registered in this class, or FALSE if none
  1473. */
  1474. function error() {
  1475. if (isset($this->err_no) && is_int($this->err_no)) {
  1476. return $this->err_no;
  1477. }
  1478. else {
  1479. return false;
  1480. }
  1481. }
  1482. }
  1483.  
  1484. ?>

Documentation generated on Sun, 16 Oct 2005 14:55:02 -0700 by phpDocumentor 1.3.0RC3