debug_str, 2 = echo() out line by line var $debug_str = ""; var $throttled = false; // set to true if server returns 503, deny any future requests var $incoming_headers = array(); var $request = ""; var $response = ""; var $cookie = false; // constructor function delicious($username,$password) { $this->username = $username; $this->password = $password; } // send http message, return parsed response function send($path) { // throttle check if($this->throttled) { $this->setError(DEL_ERR_THROTTLED); return false; } // check that credentials have been set if(!$this->username || !$this->password) { $this->setError(DEL_ERR_NOCREDENTIALS); return false; } // build http request message $msg = "GET http://".$this->host."$path HTTP/1.0\r\n" .'User-Agent: '.$this->title.'/'.$this->version."\r\n"; // cookie or credentials $msg .= 'Authorization: Basic '.base64_encode($this->username.':'.$this->password)."\r\n"; /* if(!$this->cookie) { $msg .= 'Authorization: Basic '.base64_encode($this->username.':'.$this->password)."\r\n"; } else { $msg .= 'Cookie:'.$this->cookie."\r\n"; } */ // close message $msg .= "\r\n"; $this->request = $msg; //$this->debug('REQUEST:'); //$this->debug(''.$msg.''); // make call if( $fp = pfsockopen( $this->host, $this->port) ) { if( fwrite($fp, $msg) ) { $response = ''; while (!feof($fp)) { $response .= fread($fp, 8192); } fclose($fp); $this->response = $response; //$this->debug('RESPONSE:'); //$this->debug(''.$response.''); // parse response message $pos = strpos($response,"\r\n\r\n"); if($pos < 1) { $pos = strpos($data,"\n\n"); } // separate headers and body if($headers = $this->parseHeaders(trim(substr($response,0,$pos)))) { foreach($headers as $k => $v) { $this->debug("HTTP Response Header: $k -> $v"); } // mangled headers? if(!isset($headers['status'])) { $this->debug('send(): no status in headers'); $this->setError(DEL_ERR_MANGLEDHEADERS); return false; } // handle 503 if($headers['status'] == 503) { $this->throttled = true; $this->setError(DEL_ERR_THROTTLED); return false; } // process cookie if(isset($headers['set-cookie'])) { $this->cookie = substr( $headers['set-cookie'], 0, strpos($headers['set-cookie'],';') ).';'; $this->debug('send(): setting cookie: '.$this->cookie); } // handle unchanged // get xml response $xml = trim(substr($response,$pos)); // if xml response if(strlen($xml) > 0) { $this->debug('send(): parsing xml'); // parse into assoc array and return if($result = $this->parseResponse($xml)) { return $result; } else { $this->debug('got parser error'); $this->setError(DEL_ERROR_XMLPARSE); } } else { return array(); } } else { // no proper headers found - mangled response? $this->setError(DEL_ERR_MANGLEDHEADERS); return false; } } else { $this->setError(DEL_ERR_SOCKETWRITE); return false; } } else { $this->setError(DEL_ERR_SOCKETCONNECT); return false; } } // parse headers function parseHeaders($str) { //$this->debug("parseHeaders(): header string: $str"); // find linebreak type $lb = false; $pos = strpos($str,"\r\n"); if($pos > 1){ $lb = "\r\n"; } else { $pos = strpos($str,"\n"); if($pos > 1){ $lb = "\n"; } } // if linebreak is found if(!$lb) { $this->debug('parseHeaders(): no linebreak found'); return false; } else { $header_array = explode( $lb, $str ); foreach($header_array as $header_line){ $arr = explode(':',$header_line, 2); if(count($arr) > 1){ $header_name = strtolower(trim($arr[0])); $this->incoming_headers[$header_name] = trim($arr[1]); } else if (isset($header_name)) { // append continuation line to previous header $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; } elseif ( strstr($header_line,'HTTP')) { $arr = explode(' ', $header_line); $this->incoming_headers['status'] = $arr[1]; } } return $this->incoming_headers; } } // parse response function parseResponse($xml) { $parser = xml_parser_create(''); xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0); xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,1); $return = xml_parse_into_struct($parser,$xml,$values,$tags); //$this->debug( 'parseResponse(): xml_parse_into_struct return: '.$return); // handle errors if($return == 0) { $this->debug( 'parseResponse(): xml error - '.xml_error_string( xml_get_error_code($parser) ) ); return false; } else { //$this->debug( $this->htmlvar_dump($tags) ); //$this->debug( $this->htmlvar_dump($values) ); foreach($tags as $tagname => $indices) { foreach($indices as $index) { $id = uniqid(''); if($values[$index]['type'] != 'close') { // store element details $content[$id] = $values[$index]; $tagname = $values[$index]['tag']; // set self to value of last open tag flag if($values[$index]['type'] == 'open') { $lastOpenTagAtLevel[ $values[$index]['level'] ] = $id; } // get parent id $myParent = $lastOpenTagAtLevel[ ($values[$index]['level']-1) ]; // if root, flag, and don't add to parent if($values[$index]['level'] == 1) { $root = $id; } // if complete, add self to parent result elseif($values[$index]['type'] == 'complete') { $content[ $myParent ]['result'][$tagname][] = $values[$index]['attributes']; } // if open tag, add reference to my result to parents result elseif($values[$index]['type'] == 'open') { $content[ $myParent ]['result'][$tagname][] = &$values[$index]['result']; } } } } // handle case where xml document is a single complete tag w/ no children if(!isset($content[$root]['result'])) { $result = $content[$root]['attributes']; } else { $result = array_shift($content[$root]['result']); } //$this->debug( $this->htmlvar_dump($result) ); xml_parser_free($parser); return $result; } } // set errors function setError($str) { $this->error = $str; } // get errors function getError() { return $this->error; } // handle debug output function debug($str) { if($this->debug_flag == 1) { $this->debug_str .= $str."\n"; } elseif($this->debug_flag == 2) { echo $str.'
'; } } function htmlvar_dump($var) { ob_start(); var_dump($var); $str = ob_get_contents(); ob_end_clean(); return '
'.$str.'
'; } /* function: http://del.icio.us/api/posts/dates? &tag= filter by this tag - optional returns a list of dates with the number of posts at each date. [tag] adds a filter */ function get_post_dates($tag=false) { // build path and query string $queryString = '/api/posts/dates?'; // action if($tag) { $queryString .= '&tag='.urlencode($tag); } // send return $this->send($queryString); } /* function: http://del.icio.us/api/tags/get? returns a list of tags the user has used. */ function get_tags() { // build path and query string $queryString = '/api/tags/get?'; // action // send return $this->send($queryString); } /* function: http://del.icio.us/api/posts/get? &tag= filter by this tag - optional &dt= filter by this date returns a list of posts on a given date, filtered by tag. if no date is supplied, most recent date will be used */ function get_posts($tag=false,$dt=false) { // build path and query string $queryString = '/api/posts/get?'; // action if($tag) { $queryString .= '&tag='.urlencode($tag); } if($dt) { $queryString .= '&dt='.urlencode($dt); } // send return $this->send($queryString); } /* function: http://del.icio.us/api/posts/recent? &tag= filter by this tag - optional &count= number of items to retrieve - optional (defaults to 15) returns a list of most recent posts, possibly filtered by tag. */ function get_recent_posts($tag=false,$count=false) { // build path and query string $queryString = '/api/posts/recent?'; // action if($tag) { $queryString .= '&tag='.urlencode($tag); } if($count) { $queryString .= '&count='.urlencode($count); } // send return $this->send($queryString); } /* function: http://del.icio.us/api/posts/all returns all posts. use sparingly. */ function get_all_posts() { // build path and query string $queryString = '/api/posts/all'; // action // send return $this->send($queryString); } /* function: http://del.icio.us/api/posts/add? &url= url for post &description= description for post &extended= extended for post &tags= space-delimited list of tags &dt= datestamp for post, format "CCYY-MM-DDThh:mm:ssZ" makes a post to delicious */ function add_post($link, $title, $content, $category, $date) { // prep data //$date = date('Y-m-d\TH:i:s\Z', strtotime($date) ); // build path and query string $queryString = '/api/posts/add?' // action .'&url='.$link // link for post .'&description='.urlencode($title) // description for post .'&extended='.urlencode($content) // extended for post .'&tags='.urlencode($category) // space-delimited list of tags .'&dt='.urlencode($date); // datestamp for post, format "CCYY-MM-DDThh:mm:ssZ" // send return $this->send($queryString); } /* function: http://del.icio.us/api/tags/rename? &old= old tag &new= new tag renames tags across all posts */ function rename_tag($old_tag,$new_tag) { // build path and query string $queryString = '/api/tags/rename?' // action .'&old='.urlencode($old_tag) .'&new='.urlencode($new_tag); // send return $this->send($queryString); } /* function: http://del.icio.us/api/inbox/get? &dt= filter by this date returns a list of inbox entries */ function get_inbox($dt) { // build path and query string $queryString = '/api/inbox/get?' // action .'&dt='.urlencode($dt); // send return $this->send($queryString); } /* function: http://del.icio.us/api/inbox/dates? returns a list of dates containing inbox entries */ function get_inbox_dates() { // build path and query string $queryString = '/api/inbox/dates?'; // action // send return $this->send($queryString); } /* function: http://del.icio.us/api/inbox/subs? returns a list of your subscriptions */ function get_subscriptions() { // build path and query string $queryString = '/api/inbox/subs?'; // action // send return $this->send($queryString); } /* function: http://del.icio.us/api/inbox/sub? &user= username &tag = tag - optional, leave blank for all posts adds a subscription */ function subscribe($user,$tag=false) { // build path and query string $queryString = '/api/inbox/sub?' // action .'&user='.urlencode($user); if($tag) { $queryString .= '&tag='.urlencode($tag); } // send return $this->send($queryString); } /* function: http://del.icio.us/api/inbox/unsub? &user= username &tag = tag - optional, leave blank for all posts removes a subscription */ function unsubscribe($user,$tag=false) { // build path and query string $queryString = '/api/inbox/unsub?' // action .'&user='.urlencode($user); if($tag) { $queryString .= '&tag='.urlencode($tag); } // send return $this->send($queryString); } /* function: http://del.icio.us/api/posts/delete?url= deletes a post */ function delete_post($url) { // build path and query string $queryString = '/api/posts/delete' .'?url='.urlencode($url); // send return $this->send($queryString); } } ?>