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