text:
<?php

/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage Yahoo
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Yahoo.php 23775 2011-03-01 17:25:24Z ralph $
 */

/**
 * @category   Zend
 * @package    Zend_Service
 * @subpackage Yahoo
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Service_Yahoo
{
    /**
     * Yahoo Developer Application ID
     *
     * @var string
     */
    public $appId;

    /**
     * Reference to the REST client
     *
     * @var Zend_Rest_Client
     */
    protected $_rest;

    /**
     * Sets the application ID and instantiates the REST client
     *
     * @param  string $appId specified the developer's appid
     * @return void
     */
    public function __construct($appId)
    {
        $this->appId = (string) $appId;
        /**
         * @see Zend_Rest_Client
         */
        require_once 'Zend/Rest/Client.php';
        $this->_rest = new Zend_Rest_Client('http://search.yahooapis.com');
    }

    /**
     * Retrieve Inlink Data from siteexplorer.yahoo.com.  A basic query
     * consists simply of a URL.  Additional options that can be
     * specified consist of:
     * 'results'      => int  How many results to return, max is 100
     * 'start'        => int  The start offset for search results
     * 'entire_site'  => bool  Data for the whole site or a single page
     * 'omit_inlinks' => (none|domain|subdomain)  Filter inlinks from these sources
     *
     * @param  string $query    the query being run
     * @param  array  $options  any optional parameters
     * @return Zend_Service_Yahoo_ResultSet  The return set
     * @throws Zend_Service_Exception
     */
    public function inlinkDataSearch($query, array $options = array())
    {
        static $defaultOptions = array('results'     => '50',
                                       'start'    => 1);

        $options = $this->_prepareOptions($query, $options, $defaultOptions);
        $this->_validateInlinkDataSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://search.yahooapis.com');
        $response = $this->_rest->restGet('/SiteExplorerService/V1/inlinkData', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_Yahoo_InlinkDataResultSet
         */
        require_once 'Zend/Service/Yahoo/InlinkDataResultSet.php';
        return new Zend_Service_Yahoo_InlinkDataResultSet($dom);
    }

    /**
     * Perform a search of images.  The most basic query consists simply
     * of a plain text search, but you can also specify the type of
     * image, the format, color, etc.
     *
     * The specific options are:
     * 'type'       => (all|any|phrase)  How to parse the query terms
     * 'results'    => int  How many results to return, max is 50
     * 'start'      => int  The start offset for search results
     * 'format'     => (any|bmp|gif|jpeg|png)  The type of images to search for
     * 'coloration' => (any|color|bw)  The coloration of images to search for
     * 'adult_ok'   => bool  Flag to allow 'adult' images.
     *
     * @param  string $query   the query to be run
     * @param  array  $options an optional array of query options
     * @return Zend_Service_Yahoo_ImageResultSet the search results
     * @throws Zend_Service_Exception
     */
    public function imageSearch($query, array $options = array())
    {
        static $defaultOptions = array('type'       => 'all',
                                       'results'    => 10,
                                       'start'      => 1,
                                       'format'     => 'any',
                                       'coloration' => 'any');

        $options = $this->_prepareOptions($query, $options, $defaultOptions);

        $this->_validateImageSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://search.yahooapis.com');
        $response = $this->_rest->restGet('/ImageSearchService/V1/imageSearch', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_YahooImageResultSet
         */
        require_once 'Zend/Service/Yahoo/ImageResultSet.php';
        return new Zend_Service_Yahoo_ImageResultSet($dom);
    }

    /**
     * Perform a search on local.yahoo.com.  The basic search
     * consists of a query and some fragment of location information;
     * for example zipcode, latitude/longitude, or street address.
     *
     * Query options include:
     * 'results'    => int  How many results to return, max is 50
     * 'start'      => int  The start offset for search results
     * 'sort'       => (relevance|title|distance|rating) How to order your results
     *
     * 'radius'     => float  The radius (in miles) in which to search
     *
     * 'longitude'  => float  The longitude of the location to search around
     * 'latitude'   => float  The latitude of the location to search around
     *
     * 'zip'        => string The zipcode to search around
     *
     * 'street'     => string  The street address to search around
     * 'city'       => string  The city for address search
     * 'state'      => string  The state for address search
     * 'location'   => string  An adhoc location string to search around
     *
     * @param  string $query    The query string you want to run
     * @param  array  $options  The search options, including location
     * @return Zend_Service_Yahoo_LocalResultSet The results
     * @throws Zend_Service_Exception
     */
    public function localSearch($query, array $options = array())
    {
        static $defaultOptions = array('results' => 10,
                                       'start'   => 1,
                                       'sort'    => 'distance',
                                       'radius'  => 5);

        $options = $this->_prepareOptions($query, $options, $defaultOptions);

        $this->_validateLocalSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://local.yahooapis.com');
        $response = $this->_rest->restGet('/LocalSearchService/V1/localSearch', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_Yahoo_LocalResultSet
         */
        require_once 'Zend/Service/Yahoo/LocalResultSet.php';
        return new Zend_Service_Yahoo_LocalResultSet($dom);
    }

    /**
     * Execute a search on news.yahoo.com. This method minimally takes a
     * text query to search on.
     *
     * Query options coonsist of:
     *
     * 'results'    => int  How many results to return, max is 50
     * 'start'      => int  The start offset for search results
     * 'sort'       => (rank|date)  How to order your results
     * 'language'   => lang  The target document language to match
     * 'type'       => (all|any|phrase)  How the query should be parsed
     * 'site'       => string  A site to which your search should be restricted
     *
     * @param  string $query    The query to run
     * @param  array  $options  The array of optional parameters
     * @return Zend_Service_Yahoo_NewsResultSet  The query return set
     * @throws Zend_Service_Exception
     */
    public function newsSearch($query, array $options = array())
    {
        static $defaultOptions = array('type'     => 'all',
                                       'start'    => 1,
                                       'sort'     => 'rank');

        $options = $this->_prepareOptions($query, $options, $defaultOptions);

        $this->_validateNewsSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://search.yahooapis.com');
        $response = $this->_rest->restGet('/NewsSearchService/V1/newsSearch', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_Yahoo_NewsResultSet
         */
        require_once 'Zend/Service/Yahoo/NewsResultSet.php';
        return new Zend_Service_Yahoo_NewsResultSet($dom);
    }

    /**
     * Retrieve Page Data from siteexplorer.yahoo.com.  A basic query
     * consists simply of a URL.  Additional options that can be
     * specified consist of:
     * 'results'      => int  How many results to return, max is 100
     * 'start'        => int  The start offset for search results
     * 'domain_only'  => bool  Data for just the given domain or all sub-domains also
     *
     * @param  string $query    the query being run
     * @param  array  $options  any optional parameters
     * @return Zend_Service_Yahoo_ResultSet  The return set
     * @throws Zend_Service_Exception
     */
    public function pageDataSearch($query, array $options = array())
    {
        static $defaultOptions = array('results'     => '50',
                                       'start'    => 1);

        $options = $this->_prepareOptions($query, $options, $defaultOptions);
        $this->_validatePageDataSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://search.yahooapis.com');
        $response = $this->_rest->restGet('/SiteExplorerService/V1/pageData', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_Yahoo_PageDataResultSet
         */
        require_once 'Zend/Service/Yahoo/PageDataResultSet.php';
        return new Zend_Service_Yahoo_PageDataResultSet($dom);
    }

    /**
     * Perform a search of videos.  The most basic query consists simply
     * of a plain text search, but you can also specify the format of
     * video.
     *
     * The specific options are:
     * 'type'       => (all|any|phrase)  How to parse the query terms
     * 'results'    => int  How many results to return, max is 50
     * 'start'      => int  The start offset for search results
     * 'format'     => (any|avi|flash|mpeg|msmedia|quicktime|realmedia)  The type of videos to search for
     * 'adult_ok'   => bool  Flag to allow 'adult' videos.
     *
     * @param  string $query   the query to be run
     * @param  array  $options an optional array of query options
     * @return Zend_Service_Yahoo_VideoResultSet the search results
     * @throws Zend_Service_Exception
     */
    public function videoSearch($query, array $options = array())
    {
        static $defaultOptions = array('type'       => 'all',
                                       'results'    => 10,
                                       'start'      => 1,
                                       'format'     => 'any');

        $options = $this->_prepareOptions($query, $options, $defaultOptions);

        $this->_validateVideoSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://search.yahooapis.com');
        $response = $this->_rest->restGet('/VideoSearchService/V1/videoSearch', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_YahooVideoResultSet
         */
        require_once 'Zend/Service/Yahoo/VideoResultSet.php';
        return new Zend_Service_Yahoo_VideoResultSet($dom);
    }

    /**
     * Perform a web content search on search.yahoo.com.  A basic query
     * consists simply of a text query.  Additional options that can be
     * specified consist of:
     * 'results'    => int  How many results to return, max is 50
     * 'start'      => int  The start offset for search results
     * 'language'   => lang  The target document language to match
     * 'type'       => (all|any|phrase)  How the query should be parsed
     * 'site'       => string  A site to which your search should be restricted
     * 'format'     => (any|html|msword|pdf|ppt|rss|txt|xls)
     * 'adult_ok'   => bool  permit 'adult' content in the search results
     * 'similar_ok' => bool  permit similar results in the result set
     * 'country'    => string  The country code for the content searched
     * 'license'    => (any|cc_any|cc_commercial|cc_modifiable)  The license of content being searched
     * 'region'     => The regional search engine on which the service performs the search. default us.
     *
     * @param  string $query    the query being run
     * @param  array  $options  any optional parameters
     * @return Zend_Service_Yahoo_WebResultSet  The return set
     * @throws Zend_Service_Exception
     */
    public function webSearch($query, array $options = array())
    {
        static $defaultOptions = array('type'     => 'all',
                                       'start'    => 1,
                                       'results'  => 10,
                                       'format'   => 'any');

        $options = $this->_prepareOptions($query, $options, $defaultOptions);
        $this->_validateWebSearch($options);

        $this->_rest->getHttpClient()->resetParameters();
        $this->_rest->setUri('http://search.yahooapis.com');
        $response = $this->_rest->restGet('/WebSearchService/V1/webSearch', $options);

        if ($response->isError()) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('An error occurred sending request. Status code: ' .
                                             $response->getStatus());
        }

        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());

        self::_checkErrors($dom);

        /**
         * @see Zend_Service_Yahoo_WebResultSet
         */
        require_once 'Zend/Service/Yahoo/WebResultSet.php';
        return new Zend_Service_Yahoo_WebResultSet($dom);
    }

    /**
     * Returns a reference to the REST client
     *
     * @return Zend_Rest_Client
     */
    public function getRestClient()
    {
        return $this->_rest;
    }

    /**
     * Validate Inlink Data Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateInlinkDataSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'results', 'start', 'entire_site', 'omit_inlinks');

        $this->_compareOptions($options, $validOptions);

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 100, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(100)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }

        if (isset($options['omit_inlinks'])) {
            $this->_validateInArray('omit_inlinks', $options['omit_inlinks'], array('none', 'domain', 'subdomain'));
        }
    }

    /**
     * Validate Image Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateImageSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'type', 'results', 'start', 'format', 'coloration', 'adult_ok');

        $this->_compareOptions($options, $validOptions);

        if (isset($options['type'])) {
            switch($options['type']) {
                case 'all':
                case 'any':
                case 'phrase':
                    break;
                default:
                    /**
                     * @see Zend_Service_Exception
                     */
                    require_once 'Zend/Service/Exception.php';
                    throw new Zend_Service_Exception("Invalid value for option 'type': '{$options['type']}'");
            }
        }

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 50, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(50)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }

        if (isset($options['format'])) {
            switch ($options['format']) {
                case 'any':
                case 'bmp':
                case 'gif':
                case 'jpeg':
                case 'png':
                    break;
                default:
                    /**
                     * @see Zend_Service_Exception
                     */
                    require_once 'Zend/Service/Exception.php';
                    throw new Zend_Service_Exception("Invalid value for option 'format': {$options['format']}");
            }
        }

        if (isset($options['coloration'])) {
            switch ($options['coloration']) {
                case 'any':
                case 'color':
                case 'bw':
                    break;
                default:
                    /**
                     * @see Zend_Service_Exception
                     */
                    require_once 'Zend/Service/Exception.php';
                    throw new Zend_Service_Exception("Invalid value for option 'coloration': "
                                                   . "{$options['coloration']}");
            }
        }
    }

    /**
     * Validate Local Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateLocalSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'results', 'start', 'sort', 'radius', 'street',
                              'city', 'state', 'zip', 'location', 'latitude', 'longitude');

        $this->_compareOptions($options, $validOptions);

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 20, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(20)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }

        if (isset($options['longitude']) && !$between->setMin(-90)->setMax(90)->isValid($options['longitude'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'longitude': {$options['longitude']}");
        }

        if (isset($options['latitude']) && !$between->setMin(-180)->setMax(180)->isValid($options['latitude'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'latitude': {$options['latitude']}");
        }

        if (isset($options['zip']) && !preg_match('/(^\d{5}$)|(^\d{5}-\d{4}$)/', $options['zip'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'zip': {$options['zip']}");
        }

        $hasLocation = false;
        $locationFields = array('street', 'city', 'state', 'zip', 'location');
        foreach ($locationFields as $field) {
            if (isset($options[$field]) && $options[$field] != '') {
                $hasLocation = true;
                break;
            }
        }

        if (!$hasLocation && (!isset($options['latitude']) || !isset($options['longitude']))) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('Location data are required but missing');
        }

        if (!in_array($options['sort'], array('relevance', 'title', 'distance', 'rating'))) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'sort': {$options['sort']}");
        }
    }

    /**
     * Validate News Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateNewsSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'results', 'start', 'sort', 'language', 'type', 'site');

        $this->_compareOptions($options, $validOptions);

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 50, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(50)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }

        if (isset($options['language'])) {
            $this->_validateLanguage($options['language']);
        }

        $this->_validateInArray('sort', $options['sort'], array('rank', 'date'));
        $this->_validateInArray('type', $options['type'], array('all', 'any', 'phrase'));
    }

    /**
     * Validate Page Data Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validatePageDataSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'results', 'start', 'domain_only');

        $this->_compareOptions($options, $validOptions);

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 100, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(100)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }
    }

    /**
     * Validate Video Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateVideoSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'type', 'results', 'start', 'format', 'adult_ok');

        $this->_compareOptions($options, $validOptions);

        if (isset($options['type'])) {
            $this->_validateInArray('type', $options['type'], array('all', 'any', 'phrase'));
        }

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 50, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(50)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }

        if (isset($options['format'])) {
            $this->_validateInArray('format', $options['format'], array('any', 'avi', 'flash', 'mpeg', 'msmedia', 'quicktime', 'realmedia'));
        }
    }

    /**
     * Validate Web Search Options
     *
     * @param  array $options
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateWebSearch(array $options)
    {
        $validOptions = array('appid', 'query', 'results', 'start', 'language', 'type', 'format', 'adult_ok',
                              'similar_ok', 'country', 'site', 'subscription', 'license', 'region');

        $this->_compareOptions($options, $validOptions);

        /**
         * @see Zend_Validate_Between
         */
        require_once 'Zend/Validate/Between.php';
        $between = new Zend_Validate_Between(1, 100, true);

        if (isset($options['results']) && !$between->setMin(1)->setMax(100)->isValid($options['results'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'results': {$options['results']}");
        }

        if (isset($options['start']) && !$between->setMin(1)->setMax(1000)->isValid($options['start'])) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option 'start': {$options['start']}");
        }

        if (isset($options['language'])) {
            $this->_validateLanguage($options['language']);
        }

        $this->_validateInArray('type', $options['type'], array('all', 'any', 'phrase'));
        $this->_validateInArray('format', $options['format'], array('any', 'html', 'msword', 'pdf', 'ppt', 'rss',
                                                                    'txt', 'xls'));
        if (isset($options['license'])) {
            $this->_validateInArray('license', $options['license'], array('any', 'cc_any', 'cc_commercial',
                                                                      'cc_modifiable'));
        }

        if (isset($options['region'])){
            $this->_validateInArray('region', $options['region'], array('ar', 'au', 'at', 'br', 'ca', 'ct', 'dk', 'fi',
                                                                          'fr', 'de', 'in', 'id', 'it', 'my', 'mx',
                                                                          'nl', 'no', 'ph', 'ru', 'sg', 'es', 'se',
                                                                          'ch', 'th', 'uk', 'us'));
        }
    }

    /**
     * Prepare options for sending to Yahoo!
     *
     * @param  string $query          Search Query
     * @param  array  $options        User specified options
     * @param  array  $defaultOptions Required/Default options
     * @return array
     */
    protected function _prepareOptions($query, array $options, array $defaultOptions = array())
    {
        $options['appid'] = $this->appId;
        $options['query'] = (string) $query;

        return array_merge($defaultOptions, $options);
    }

    /**
     * Throws an exception if the chosen language is not supported
     *
     * @param  string $lang Language code
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateLanguage($lang)
    {
        $languages = array('ar', 'bg', 'ca', 'szh', 'tzh', 'hr', 'cs', 'da', 'nl', 'en', 'et', 'fi', 'fr', 'de', 'el',
            'he', 'hu', 'is', 'id', 'it', 'ja', 'ko', 'lv', 'lt', 'no', 'fa', 'pl', 'pt', 'ro', 'ru', 'sk', 'sr', 'sl',
            'es', 'sv', 'th', 'tr'
            );
        if (!in_array($lang, $languages)) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("The selected language '$lang' is not supported");
        }
    }

    /**
     * Utility function to check for a difference between two arrays.
     *
     * @param  array $options      User specified options
     * @param  array $validOptions Valid options
     * @return void
     * @throws Zend_Service_Exception if difference is found (e.g., unsupported query option)
     */
    protected function _compareOptions(array $options, array $validOptions)
    {
        $difference = array_diff(array_keys($options), $validOptions);
        if ($difference) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception('The following parameters are invalid: ' . join(', ', $difference));
        }
    }

    /**
     * Check that a named value is in the given array
     *
     * @param  string $name  Name associated with the value
     * @param  mixed  $value Value
     * @param  array  $array Array in which to check for the value
     * @return void
     * @throws Zend_Service_Exception
     */
    protected function _validateInArray($name, $value, array $array)
    {
        if (!in_array($value, $array)) {
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception("Invalid value for option '$name': $value");
        }
    }

    /**
     * Check if response is an error
     *
     * @param  DOMDocument $dom DOM Object representing the result XML
     * @return void
     * @throws Zend_Service_Exception Thrown when the result from Yahoo! is an error
     */
    protected static function _checkErrors(DOMDocument $dom)
    {
        $xpath = new DOMXPath($dom);
        $xpath->registerNamespace('yapi', 'urn:yahoo:api');

        if ($xpath->query('//yapi:Error')->length >= 1) {
            $message = $xpath->query('//yapi:Error/yapi:Message/text()')->item(0)->data;
            /**
             * @see Zend_Service_Exception
             */
            require_once 'Zend/Service/Exception.php';
            throw new Zend_Service_Exception($message);
        }
    }
}


text:
<?php

/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage Technorati
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Technorati.php 23775 2011-03-01 17:25:24Z ralph $
 */

/**
 * Zend_Service_Technorati provides an easy, intuitive and object-oriented interface
 * for using the Technorati API.
 *
 * It provides access to all available Technorati API queries
 * and returns the original XML response as a friendly PHP object.
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage Technorati
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Service_Technorati
{
    /** Base Technorati API URI */
    const API_URI_BASE = 'http://api.technorati.com';

    /** Query paths */
    const API_PATH_COSMOS           = '/cosmos';
    const API_PATH_SEARCH           = '/search';
    const API_PATH_TAG              = '/tag';
    const API_PATH_DAILYCOUNTS      = '/dailycounts';
    const API_PATH_TOPTAGS          = '/toptags';
    const API_PATH_BLOGINFO         = '/bloginfo';
    const API_PATH_BLOGPOSTTAGS     = '/blogposttags';
    const API_PATH_GETINFO          = '/getinfo';
    const API_PATH_KEYINFO          = '/keyinfo';

    /** Prevent magic numbers */
    const PARAM_LIMIT_MIN_VALUE = 1;
    const PARAM_LIMIT_MAX_VALUE = 100;
    const PARAM_DAYS_MIN_VALUE  = 1;
    const PARAM_DAYS_MAX_VALUE  = 180;
    const PARAM_START_MIN_VALUE = 1;

    /**
     * Technorati API key
     *
     * @var     string
     * @access  protected
     */
    protected $_apiKey;

    /**
     * Zend_Rest_Client instance
     *
     * @var     Zend_Rest_Client
     * @access  protected
     */
    protected $_restClient;

    /**
     * Constructs a new Zend_Service_Technorati instance
     * and setup character encoding.
     *
     * @param  string $apiKey  Your Technorati API key
     */
    public function __construct($apiKey)
    {
        iconv_set_encoding('output_encoding', 'UTF-8');
        iconv_set_encoding('input_encoding', 'UTF-8');
        iconv_set_encoding('internal_encoding', 'UTF-8');

        $this->_apiKey = $apiKey;
    }

    /**
     * Cosmos query lets you see what blogs are linking to a given URL.
     *
     * On the Technorati site, you can enter a URL in the searchbox and
     * it will return a list of blogs linking to it.
     * The API version allows more features and gives you a way
     * to use the cosmos on your own site.
     *
     * Query options include:
     *
     * 'type'       => (link|weblog)
     *      optional - A value of link returns the freshest links referencing your target URL.
     *      A value of weblog returns the last set of unique weblogs referencing your target URL.
     * 'limit'      => (int)
     *      optional - adjust the size of your result from the default value of 20
     *      to between 1 and 100 results.
     * 'start'      => (int)
     *      optional - adjust the range of your result set.
     *      Set this number to larger than zero and you will receive
     *      the portion of Technorati's total result set ranging from start to start+limit.
     *      The default start value is 1.
     * 'current'    => (true|false)
     *      optional - the default setting of true
     *      Technorati returns links that are currently on a weblog's homepage.
     *      Set this parameter to false if you would like to receive all links
     *      to the given URL regardless of their current placement on the source blog.
     *      Internally the value is converted in (yes|no).
     * 'claim'      => (true|false)
     *      optional - the default setting of FALSE returns no user information
     *      about each weblog included in the result set when available.
     *      Set this parameter to FALSE to include Technorati member data
     *      in the result set when a weblog in your result set
     *      has been successfully claimed by a member of Technorati.
     *      Internally the value is converted in (int).
     * 'highlight'  => (true|false)
     *      optional - the default setting of TRUE
     *      highlights the citation of the given URL within the weblog excerpt.
     *      Set this parameter to FALSE to apply no special markup to the blog excerpt.
     *      Internally the value is converted in (int).
     *
     * @param   string $url     the URL you are searching for. Prefixes http:// and www. are optional.
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_CosmosResultSet
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/cosmos.html Technorati API: Cosmos Query reference
     */
    public function cosmos($url, $options = null)
    {
        static $defaultOptions = array( 'type'      => 'link',
                                        'start'     => 1,
                                        'limit'     => 20,
                                        'current'   => 'yes',
                                        'format'    => 'xml',
                                        'claim'     => 0,
                                        'highlight' => 1,
                                        );

        $options['url'] = $url;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateCosmos($options);
        $response = $this->_makeRequest(self::API_PATH_COSMOS, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_CosmosResultSet
         */
        require_once 'Zend/Service/Technorati/CosmosResultSet.php';
        return new Zend_Service_Technorati_CosmosResultSet($dom, $options);
    }

    /**
     * Search lets you see what blogs contain a given search string.
     *
     * Query options include:
     *
     * 'language'   => (string)
     *      optional - a ISO 639-1 two character language code
     *      to retrieve results specific to that language.
     *      This feature is currently beta and may not work for all languages.
     * 'authority'  => (n|a1|a4|a7)
     *      optional - filter results to those from blogs with at least
     *      the Technorati Authority specified.
     *      Technorati calculates a blog's authority by how many people link to it.
     *      Filtering by authority is a good way to refine your search results.
     *      There are four settings:
     *      - n  => Any authority: All results.
     *      - a1 => A little authority: Results from blogs with at least one link.
     *      - a4 => Some authority: Results from blogs with a handful of links.
     *      - a7 => A lot of authority: Results from blogs with hundreds of links.
     * 'limit'      => (int)
     *      optional - adjust the size of your result from the default value of 20
     *      to between 1 and 100 results.
     * 'start'      => (int)
     *      optional - adjust the range of your result set.
     *      Set this number to larger than zero and you will receive
     *      the portion of Technorati's total result set ranging from start to start+limit.
     *      The default start value is 1.
     * 'claim'      => (true|false)
     *      optional - the default setting of FALSE returns no user information
     *      about each weblog included in the result set when available.
     *      Set this parameter to FALSE to include Technorati member data
     *      in the result set when a weblog in your result set
     *      has been successfully claimed by a member of Technorati.
     *      Internally the value is converted in (int).
     *
     * @param   string $query   the words you are searching for.
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_SearchResultSet
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/search.html Technorati API: Search Query reference
     */
    public function search($query, $options = null)
    {
        static $defaultOptions = array( 'start'     => 1,
                                        'limit'     => 20,
                                        'format'    => 'xml',
                                        'claim'     => 0);

        $options['query'] = $query;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateSearch($options);
        $response = $this->_makeRequest(self::API_PATH_SEARCH, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_SearchResultSet
         */
        require_once 'Zend/Service/Technorati/SearchResultSet.php';
        return new Zend_Service_Technorati_SearchResultSet($dom, $options);
    }

    /**
     * Tag lets you see what posts are associated with a given tag.
     *
     * Query options include:
     *
     * 'limit'          => (int)
     *      optional - adjust the size of your result from the default value of 20
     *      to between 1 and 100 results.
     * 'start'          => (int)
     *      optional - adjust the range of your result set.
     *      Set this number to larger than zero and you will receive
     *      the portion of Technorati's total result set ranging from start to start+limit.
     *      The default start value is 1.
     * 'excerptsize'    => (int)
     *      optional - number of word characters to include in the post excerpts.
     *      By default 100 word characters are returned.
     * 'topexcerptsize' => (int)
     *      optional - number of word characters to include in the first post excerpt.
     *      By default 150 word characters are returned.
     *
     * @param   string $tag     the tag term you are searching posts for.
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_TagResultSet
     * @throws  Zend_Service_Technorati_Exception
     *  @link    http://technorati.com/developers/api/tag.html Technorati API: Tag Query reference
     */
    public function tag($tag, $options = null)
    {
        static $defaultOptions = array( 'start'          => 1,
                                        'limit'          => 20,
                                        'format'         => 'xml',
                                        'excerptsize'    => 100,
                                        'topexcerptsize' => 150);

        $options['tag'] = $tag;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateTag($options);
        $response = $this->_makeRequest(self::API_PATH_TAG, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_TagResultSet
         */
        require_once 'Zend/Service/Technorati/TagResultSet.php';
        return new Zend_Service_Technorati_TagResultSet($dom, $options);
    }

    /**
     * TopTags provides daily counts of posts containing the queried keyword.
     *
     * Query options include:
     *
     * 'days'       => (int)
     *      optional - Used to specify the number of days in the past
     *      to request daily count data for.
     *      Can be any integer between 1 and 180, default is 180
     *
     * @param   string $q       the keyword query
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_DailyCountsResultSet
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/dailycounts.html Technorati API: DailyCounts Query reference
     */
    public function dailyCounts($query, $options = null)
    {
        static $defaultOptions = array( 'days'      => 180,
                                        'format'    => 'xml'
                                        );

        $options['q'] = $query;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateDailyCounts($options);
        $response = $this->_makeRequest(self::API_PATH_DAILYCOUNTS, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_DailyCountsResultSet
         */
        require_once 'Zend/Service/Technorati/DailyCountsResultSet.php';
        return new Zend_Service_Technorati_DailyCountsResultSet($dom);
    }

    /**
     * TopTags provides information on top tags indexed by Technorati.
     *
     * Query options include:
     *
     * 'limit'      => (int)
     *      optional - adjust the size of your result from the default value of 20
     *      to between 1 and 100 results.
     * 'start'      => (int)
     *      optional - adjust the range of your result set.
     *      Set this number to larger than zero and you will receive
     *      the portion of Technorati's total result set ranging from start to start+limit.
     *      The default start value is 1.
     *
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_TagsResultSet
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/toptags.html Technorati API: TopTags Query reference
     */
    public function topTags($options = null)
    {
        static $defaultOptions = array( 'start'     => 1,
                                        'limit'     => 20,
                                        'format'    => 'xml'
                                        );

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateTopTags($options);
        $response = $this->_makeRequest(self::API_PATH_TOPTAGS, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_TagsResultSet
         */
        require_once 'Zend/Service/Technorati/TagsResultSet.php';
        return new Zend_Service_Technorati_TagsResultSet($dom);
    }

    /**
     * BlogInfo provides information on what blog, if any, is associated with a given URL.
     *
     * @param   string $url     the URL you are searching for. Prefixes http:// and www. are optional.
     *                          The URL must be recognized by Technorati as a blog.
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_BlogInfoResult
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/bloginfo.html Technorati API: BlogInfo Query reference
     */
    public function blogInfo($url, $options = null)
    {
        static $defaultOptions = array( 'format'    => 'xml'
                                        );

        $options['url'] = $url;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateBlogInfo($options);
        $response = $this->_makeRequest(self::API_PATH_BLOGINFO, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_BlogInfoResult
         */
        require_once 'Zend/Service/Technorati/BlogInfoResult.php';
        return new Zend_Service_Technorati_BlogInfoResult($dom);
    }

    /**
     * BlogPostTags provides information on the top tags used by a specific blog.
     *
     * Query options include:
     *
     * 'limit'      => (int)
     *      optional - adjust the size of your result from the default value of 20
     *      to between 1 and 100 results.
     * 'start'      => (int)
     *      optional - adjust the range of your result set.
     *      Set this number to larger than zero and you will receive
     *      the portion of Technorati's total result set ranging from start to start+limit.
     *      The default start value is 1.
     *      Note. This property is not documented.
     *
     * @param   string $url     the URL you are searching for. Prefixes http:// and www. are optional.
     *                          The URL must be recognized by Technorati as a blog.
     * @param   array $options  additional parameters to refine your query
     * @return  Zend_Service_Technorati_TagsResultSet
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/blogposttags.html Technorati API: BlogPostTags Query reference
     */
    public function blogPostTags($url, $options = null)
    {
        static $defaultOptions = array( 'start'     => 1,
                                        'limit'     => 20,
                                        'format'    => 'xml'
                                        );

        $options['url'] = $url;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateBlogPostTags($options);
        $response = $this->_makeRequest(self::API_PATH_BLOGPOSTTAGS, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_TagsResultSet
         */
        require_once 'Zend/Service/Technorati/TagsResultSet.php';
        return new Zend_Service_Technorati_TagsResultSet($dom);
    }

    /**
     * GetInfo query tells you things that Technorati knows about a member.
     *
     * The returned info is broken up into two sections:
     * The first part describes some information that the user wants
     * to allow people to know about him- or herself.
     * The second part of the document is a listing of the weblogs
     * that the user has successfully claimed and the information
     * that Technorati knows about these weblogs.
     *
     * @param   string $username    the Technorati user name you are searching for
     * @param   array $options      additional parameters to refine your query
     * @return  Zend_Service_Technorati_GetInfoResult
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/getinfo.html Technorati API: GetInfo reference
     */
    public function getInfo($username, $options = null)
    {
        static $defaultOptions = array('format' => 'xml');

        $options['username'] = $username;

        $options = $this->_prepareOptions($options, $defaultOptions);
        $this->_validateGetInfo($options);
        $response = $this->_makeRequest(self::API_PATH_GETINFO, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_GetInfoResult
         */
        require_once 'Zend/Service/Technorati/GetInfoResult.php';
        return new Zend_Service_Technorati_GetInfoResult($dom);
    }

    /**
     * KeyInfo query provides information on daily usage of an API key.
     * Key Info Queries do not count against a key's daily query limit.
     *
     * A day is defined as 00:00-23:59 Pacific time.
     *
     * @return  Zend_Service_Technorati_KeyInfoResult
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://developers.technorati.com/wiki/KeyInfo Technorati API: Key Info reference
     */
    public function keyInfo()
    {
        static $defaultOptions = array();

        $options = $this->_prepareOptions(array(), $defaultOptions);
        // you don't need to validate this request
        // because key is the only mandatory element
        // and it's already set in #_prepareOptions
        $response = $this->_makeRequest(self::API_PATH_KEYINFO, $options);
        $dom = $this->_convertResponseAndCheckContent($response);

        /**
         * @see Zend_Service_Technorati_KeyInfoResult
         */
        require_once 'Zend/Service/Technorati/KeyInfoResult.php';
        return new Zend_Service_Technorati_KeyInfoResult($dom, $this->_apiKey);
    }

    /**
     * Returns Technorati API key.
     *
     * @return string   Technorati API key
     */
    public function getApiKey()
    {
        return $this->_apiKey;
    }

    /**
     * Returns a reference to the REST client object in use.
     *
     * If the reference hasn't being inizialized yet,
     * then a new Zend_Rest_Client instance is created.
     *
     * @return Zend_Rest_Client
     */
    public function getRestClient()
    {
        if ($this->_restClient === null) {
            /**
             * @see Zend_Rest_Client
             */
            require_once 'Zend/Rest/Client.php';
            $this->_restClient = new Zend_Rest_Client(self::API_URI_BASE);
        }

        return $this->_restClient;
    }

    /**
     * Sets Technorati API key.
     *
     * Be aware that this function doesn't validate the key.
     * The key is validated as soon as the first API request is sent.
     * If the key is invalid, the API request method will throw
     * a Zend_Service_Technorati_Exception exception with Invalid Key message.
     *
     * @param   string $key     Technorati API Key
     * @return  void
     * @link    http://technorati.com/developers/apikey.html How to get your Technorati API Key
     */
    public function setApiKey($key)
    {
        $this->_apiKey = $key;
        return $this;
    }

    /**
     * Validates Cosmos query options.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateCosmos(array $options)
    {
        static $validOptions = array('key', 'url',
            'type', 'limit', 'start', 'current', 'claim', 'highlight', 'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate url (required)
        $this->_validateOptionUrl($options);
        // Validate limit (optional)
        $this->_validateOptionLimit($options);
        // Validate start (optional)
        $this->_validateOptionStart($options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
        // Validate type (optional)
        $this->_validateInArrayOption('type', $options, array('link', 'weblog'));
        // Validate claim (optional)
        $this->_validateOptionClaim($options);
        // Validate highlight (optional)
        $this->_validateIntegerOption('highlight', $options);
        // Validate current (optional)
        if (isset($options['current'])) {
            $tmp = (int) $options['current'];
            $options['current'] = $tmp ? 'yes' : 'no';
        }

    }

    /**
     * Validates Search query options.
     *
     * @param   array   $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateSearch(array $options)
    {
        static $validOptions = array('key', 'query',
            'language', 'authority', 'limit', 'start', 'claim', 'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate query (required)
        $this->_validateMandatoryOption('query', $options);
        // Validate authority (optional)
        $this->_validateInArrayOption('authority', $options, array('n', 'a1', 'a4', 'a7'));
        // Validate limit (optional)
        $this->_validateOptionLimit($options);
        // Validate start (optional)
        $this->_validateOptionStart($options);
        // Validate claim (optional)
        $this->_validateOptionClaim($options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
    }

    /**
     * Validates Tag query options.
     *
     * @param   array   $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateTag(array $options)
    {
        static $validOptions = array('key', 'tag',
            'limit', 'start', 'excerptsize', 'topexcerptsize', 'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate query (required)
        $this->_validateMandatoryOption('tag', $options);
        // Validate limit (optional)
        $this->_validateOptionLimit($options);
        // Validate start (optional)
        $this->_validateOptionStart($options);
        // Validate excerptsize (optional)
        $this->_validateIntegerOption('excerptsize', $options);
        // Validate excerptsize (optional)
        $this->_validateIntegerOption('topexcerptsize', $options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
    }

    /**
     * Validates DailyCounts query options.
     *
     * @param   array   $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateDailyCounts(array $options)
    {
        static $validOptions = array('key', 'q',
            'days', 'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate q (required)
        $this->_validateMandatoryOption('q', $options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
        // Validate days (optional)
        if (isset($options['days'])) {
            $options['days'] = (int) $options['days'];
            if ($options['days'] < self::PARAM_DAYS_MIN_VALUE ||
                $options['days'] > self::PARAM_DAYS_MAX_VALUE) {
                /**
                 * @see Zend_Service_Technorati_Exception
                 */
                require_once 'Zend/Service/Technorati/Exception.php';
                throw new Zend_Service_Technorati_Exception(
                            "Invalid value '" . $options['days'] . "' for 'days' option");
            }
        }
    }

    /**
     * Validates GetInfo query options.
     *
     * @param   array   $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateGetInfo(array $options)
    {
        static $validOptions = array('key', 'username',
            'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate username (required)
        $this->_validateMandatoryOption('username', $options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
    }

    /**
     * Validates TopTags query options.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateTopTags(array $options)
    {
        static $validOptions = array('key',
            'limit', 'start', 'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate limit (optional)
        $this->_validateOptionLimit($options);
        // Validate start (optional)
        $this->_validateOptionStart($options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
    }

    /**
     * Validates BlogInfo query options.
     *
     * @param   array   $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateBlogInfo(array $options)
    {
        static $validOptions = array('key', 'url',
            'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate url (required)
        $this->_validateOptionUrl($options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
    }

    /**
     * Validates TopTags query options.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateBlogPostTags(array $options)
    {
        static $validOptions = array('key', 'url',
            'limit', 'start', 'format');

        // Validate keys in the $options array
        $this->_compareOptions($options, $validOptions);
        // Validate url (required)
        $this->_validateOptionUrl($options);
        // Validate limit (optional)
        $this->_validateOptionLimit($options);
        // Validate start (optional)
        $this->_validateOptionStart($options);
        // Validate format (optional)
        $this->_validateOptionFormat($options);
    }

    /**
     * Checks whether an option is in a given array.
     *
     * @param   string $name    option name
     * @param   array $options
     * @param   array $array    array of valid options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateInArrayOption($name, $options, array $array)
    {
        if (isset($options[$name]) && !in_array($options[$name], $array)) {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(
                        "Invalid value '{$options[$name]}' for '$name' option");
        }
    }

    /**
     * Checks whether mandatory $name option exists and it's valid.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _validateMandatoryOption($name, $options)
    {
        if (!isset($options[$name]) || !trim($options[$name])) {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(
                        "Empty value for '$name' option");
        }
    }

    /**
     * Checks whether $name option is a valid integer and casts it.
     *
     * @param   array $options
     * @return  void
     * @access  protected
     */
    protected function _validateIntegerOption($name, $options)
    {
        if (isset($options[$name])) {
            $options[$name] = (int) $options[$name];
        }
    }

    /**
     * Makes and HTTP GET request to given $path with $options.
     * HTTP Response is first validated, then returned.
     *
     * @param   string $path
     * @param   array $options
     * @return  Zend_Http_Response
     * @throws  Zend_Service_Technorati_Exception on failure
     * @access  protected
     */
    protected function _makeRequest($path, $options = array())
    {
        $restClient = $this->getRestClient();
        $restClient->getHttpClient()->resetParameters();
        $response = $restClient->restGet($path, $options);
        self::_checkResponse($response);
        return $response;
    }

    /**
     * Checks whether 'claim' option value is valid.
     *
     * @param   array $options
     * @return  void
     * @access  protected
     */
    protected function _validateOptionClaim(array $options)
    {
        $this->_validateIntegerOption('claim', $options);
    }

    /**
     * Checks whether 'format' option value is valid.
     * Be aware that Zend_Service_Technorati supports only XML as format value.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception if 'format' value != XML
     * @access  protected
     */
    protected function _validateOptionFormat(array $options)
    {
        if (isset($options['format']) && $options['format'] != 'xml') {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(
                        "Invalid value '" . $options['format'] . "' for 'format' option. " .
                        "Zend_Service_Technorati supports only 'xml'");
        }
    }

    /**
     * Checks whether 'limit' option value is valid.
     * Value must be an integer greater than PARAM_LIMIT_MIN_VALUE
     * and lower than PARAM_LIMIT_MAX_VALUE.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception if 'limit' value is invalid
     * @access  protected
     */
    protected function _validateOptionLimit(array $options)
    {
        if (!isset($options['limit'])) return;

        $options['limit'] = (int) $options['limit'];
        if ($options['limit'] < self::PARAM_LIMIT_MIN_VALUE ||
            $options['limit'] > self::PARAM_LIMIT_MAX_VALUE) {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(
                        "Invalid value '" . $options['limit'] . "' for 'limit' option");
        }
    }

    /**
     * Checks whether 'start' option value is valid.
     * Value must be an integer greater than 0.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception if 'start' value is invalid
     * @access  protected
     */
    protected function _validateOptionStart(array $options)
    {
        if (!isset($options['start'])) return;

        $options['start'] = (int) $options['start'];
        if ($options['start'] < self::PARAM_START_MIN_VALUE) {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(
                        "Invalid value '" . $options['start'] . "' for 'start' option");
        }
    }

    /**
     * Checks whether 'url' option value exists and is valid.
     * 'url' must be a valid HTTP(s) URL.
     *
     * @param   array $options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception if 'url' value is invalid
     * @access  protected
     * @todo    support for Zend_Uri_Http
     */
    protected function _validateOptionUrl(array $options)
    {
        $this->_validateMandatoryOption('url', $options);
    }

    /**
     * Checks XML response content for errors.
     *
     * @param   DomDocument $dom    the XML response as a DOM document
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @link    http://technorati.com/developers/api/error.html Technorati API: Error response
     * @access  protected
     */
    protected static function _checkErrors(DomDocument $dom)
    {
        $xpath = new DOMXPath($dom);

        $result = $xpath->query("/tapi/document/result/error");
        if ($result->length >= 1) {
            $error = $result->item(0)->nodeValue;
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception($error);
        }
    }

    /**
     * Converts $response body to a DOM object and checks it.
     *
     * @param   Zend_Http_Response $response
     * @return  DOMDocument
     * @throws  Zend_Service_Technorati_Exception if response content contains an error message
     * @access  protected
     */
    protected function _convertResponseAndCheckContent(Zend_Http_Response $response)
    {
        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());
        self::_checkErrors($dom);
        return $dom;
    }

    /**
     * Checks ReST response for errors.
     *
     * @param   Zend_Http_Response $response    the ReST response
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected static function _checkResponse(Zend_Http_Response $response)
    {
        if ($response->isError()) {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(sprintf(
                        'Invalid response status code (HTTP/%s %s %s)',
                        $response->getVersion(), $response->getStatus(), $response->getMessage()));
        }
    }

    /**
     * Checks whether user given options are valid.
     *
     * @param   array $options        user options
     * @param   array $validOptions   valid options
     * @return  void
     * @throws  Zend_Service_Technorati_Exception
     * @access  protected
     */
    protected function _compareOptions(array $options, array $validOptions)
    {
        $difference = array_diff(array_keys($options), $validOptions);
        if ($difference) {
            /**
             * @see Zend_Service_Technorati_Exception
             */
            require_once 'Zend/Service/Technorati/Exception.php';
            throw new Zend_Service_Technorati_Exception(
                        "The following parameters are invalid: '" .
                        implode("', '", $difference) . "'");
        }
    }

    /**
     * Prepares options for the request
     *
     * @param   array $options        user options
     * @param   array $defaultOptions default options
     * @return  array Merged array of user and default/required options.
     * @access  protected
     */
    protected function _prepareOptions($options, array $defaultOptions)
    {
        $options = (array) $options; // force cast to convert null to array()
        $options['key'] = $this->_apiKey;
        $options = array_merge($defaultOptions, $options);
        return $options;
    }
}

repo_name: michael-romer/zf-boilerplate

repo_language: PHP

mime_type: text/html


text:
<?php

/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage Delicious
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Delicious.php 23775 2011-03-01 17:25:24Z ralph $
 */

/**
 * @see Zend_Rest_Client
 */
require_once 'Zend/Rest/Client.php';

/**
 * @see Zend_Json_Decoder
 */
require_once 'Zend/Json/Decoder.php';

/**
 * @see Zend_Service_Delicious_SimplePost
 */
require_once 'Zend/Service/Delicious/SimplePost.php';

/**
 * @see Zend_Service_Delicious_Post
 */
require_once 'Zend/Service/Delicious/Post.php';

/**
 * @see Zend_Service_Delicious_PostList
 */
require_once 'Zend/Service/Delicious/PostList.php';

/**
 * Zend_Service_Delicious is a concrete implementation of the del.icio.us web service
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage Delicious
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Service_Delicious
{
    const API_URI = 'https://api.del.icio.us';

    const PATH_UPDATE        = '/v1/posts/update';
    const PATH_TAGS          = '/v1/tags/get';
    const PATH_TAG_RENAME    = '/v1/tags/rename';
    const PATH_BUNDLES       = '/v1/tags/bundles/all';
    const PATH_BUNDLE_DELETE = '/v1/tags/bundles/delete';
    const PATH_BUNDLE_ADD    = '/v1/tags/bundles/set';
    const PATH_DATES         = '/v1/posts/dates';
    const PATH_POST_DELETE   = '/v1/posts/delete';
    const PATH_POSTS_GET     = '/v1/posts/get';
    const PATH_POSTS_ALL     = '/v1/posts/all';
    const PATH_POSTS_ADD     = '/v1/posts/add';
    const PATH_POSTS_RECENT  = '/v1/posts/recent';

    const JSON_URI     = 'http://del.icio.us';
    const JSON_POSTS   = '/feeds/json/%s/%s';
    const JSON_TAGS    = '/feeds/json/tags/%s';
    const JSON_NETWORK = '/feeds/json/network/%s';
    const JSON_FANS    = '/feeds/json/fans/%s';
    const JSON_URL     = '/feeds/json/url/data';

    /**
     * Zend_Service_Rest instance
     *
     * @var Zend_Service_Rest
     */
    protected $_rest;

    /**
     * Username
     *
     * @var string
     */
    protected $_authUname;

    /**
     * Password
     *
     * @var string
     */
    protected $_authPass;

    /**
     * Microtime of last request
     *
     * @var float
     */
    protected static $_lastRequestTime = 0;

    /**
     * Constructs a new del.icio.us Web Services Client
     *
     * @param  string $uname Client username
     * @param  string $pass  Client password
     * @return void
     */
    public function __construct($uname = null, $pass = null)
    {
        $this->_rest = new Zend_Rest_Client();
        $this->_rest->getHttpClient()->setConfig(array('ssltransport' => 'ssl'));
        $this->setAuth($uname, $pass);
    }

    /**
     * Set client username and password
     *
     * @param  string $uname Client user name
     * @param  string $pass  Client password
     * @return Zend_Service_Delicious Provides a fluent interface
     */
    public function setAuth($uname, $pass)
    {
        $this->_authUname = $uname;
        $this->_authPass  = $pass;

        return $this;
    }

    /**
     * Get time of the last update
     *
     * @throws Zend_Service_Delicious_Exception
     * @return Zend_Date
     */
    public function getLastUpdate()
    {
        $response = $this->makeRequest(self::PATH_UPDATE);

        $rootNode = $response->documentElement;
        if ($rootNode && $rootNode->nodeName == 'update') {
            /**
             * @todo replace strtotime() with Zend_Date equivalent
             */
            return new Zend_Date(strtotime($rootNode->getAttribute('time')));
        } else {
            /**
             * @see Zend_Service_Delicious_Exception
             */
            require_once 'Zend/Service/Delicious/Exception.php';
            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
        }
    }

    /**
     * Get all tags, returning an array with tags as keys and number of corresponding posts as values
     *
     * @return array list of tags
     */
    public function getTags()
    {
        $response = $this->makeRequest(self::PATH_TAGS);

        return self::_xmlResponseToArray($response, 'tags', 'tag', 'tag', 'count');
    }

    /**
     * Rename a tag
     *
     * @param  string $old Old tag name
     * @param  string $new New tag name
     * @return Zend_Service_Delicious Provides a fluent interface
     */
    public function renameTag($old, $new)
    {
        $response = $this->makeRequest(self::PATH_TAG_RENAME, array('old' => $old, 'new' => $new));

        self::_evalXmlResult($response);

        return $this;
    }

    /**
     * Get all bundles, returning an array with bundles as keys and array of tags as values
     *
     * @return array list of bundles
     */
    public function getBundles()
    {
        $response = $this->makeRequest(self::PATH_BUNDLES);

        $bundles = self::_xmlResponseToArray($response, 'bundles', 'bundle', 'name', 'tags');
        foreach ($bundles as &$tags) {
            $tags = explode(' ', $tags);
        }
        return $bundles;
    }

    /**
     * Adds a new bundle
     *
     * @param  string $bundle Name of new bundle
     * @param  array  $tags   Array of tags
     * @return Zend_Service_Delicious Provides a fluent interface
     */
    public function addBundle($bundle, array $tags)
    {
        $tags = implode(' ', (array) $tags);
        $response = $this->makeRequest(self::PATH_BUNDLE_ADD, array('bundle' => $bundle, 'tags' => $tags));

        self::_evalXmlResult($response);

        return $this;
    }

    /**
     * Delete a bundle
     *
     * @param  string $bundle Name of bundle to be deleted
     * @return Zend_Service_Delicious Provides a fluent interface
     */
    public function deleteBundle($bundle)
    {
        $response = $this->makeRequest(self::PATH_BUNDLE_DELETE, array('bundle' => $bundle));

        self::_evalXmlResult($response);

        return $this;
    }

    /**
     * Delete a post
     *
     * @param  string $url URL of post to be deleted
     * @return Zend_Service_Delicious Provides a fluent interface
     */
    public function deletePost($url)
    {
        $response = $this->makeRequest(self::PATH_POST_DELETE, array('url' => $url));

        self::_evalXmlResult($response);

        return $this;
    }

    /**
     * Get number of posts by date
     *
     * Returns array where keys are dates and values are numbers of posts
     *
     * @param  string $tag Optional filtering by tag
     * @return array list of dates
     */
    public function getDates($tag = null)
    {
        $parms = array();
        if ($tag) {
            $parms['tag'] = $tag;
        }

        $response = $this->makeRequest(self::PATH_DATES, $parms);

        return self::_xmlResponseToArray($response, 'dates', 'date', 'date', 'count');
    }

    /**
     * Get posts matching the arguments
     *
     * If no date or url is given, most recent date will be used
     *
     * @param  string    $tag Optional filtering by tag
     * @param  Zend_Date $dt  Optional filtering by date
     * @param  string    $url Optional filtering by url
     * @throws Zend_Service_Delicious_Exception
     * @return Zend_Service_Delicious_PostList
     */
    public function getPosts($tag = null, Zend_Date $dt = null, $url = null)
    {
        $parms = array();
        if ($tag) {
            $parms['tag'] = $tag;
        }
        if ($url) {
            $parms['url'] = $url;
        }
        if ($dt) {
            $parms['dt'] = $dt->get('Y-m-d\TH:i:s\Z');
        }

        $response = $this->makeRequest(self::PATH_POSTS_GET, $parms);

        return $this->_parseXmlPostList($response);
    }

    /**
     * Get all posts
     *
     * @param  string $tag Optional filtering by tag
     * @return Zend_Service_Delicious_PostList
     */
    public function getAllPosts($tag = null)
    {
        $parms = array();
        if ($tag) {
            $parms['tag'] = $tag;
        }

        $response = $this->makeRequest(self::PATH_POSTS_ALL, $parms);

        return $this->_parseXmlPostList($response);
    }

    /**
     * Get recent posts
     *
     * @param  string $tag   Optional filtering by tag
     * @param  string $count Maximum number of posts to be returned (default 15)
     * @return Zend_Service_Delicious_PostList
     */
    public function getRecentPosts($tag = null, $count = 15)
    {
        $parms = array();
        if ($tag) {
            $parms['tag'] = $tag;
        }
        if ($count) {
            $parms['count'] = $count;
        }

        $response = $this->makeRequest(self::PATH_POSTS_RECENT, $parms);

        return $this->_parseXmlPostList($response);
    }

    /**
     * Create new post
     *
     * @return Zend_Service_Delicious_Post
     */
    public function createNewPost($title, $url)
    {
        return new Zend_Service_Delicious_Post($this, array('title' => $title, 'url' => $url));
    }

    /**
     * Get posts of a user
     *
     * @param  string $user  Owner of the posts
     * @param  int    $count Number of posts (default 15, max. 100)
     * @param  string $tag   Optional filtering by tag
     * @return Zend_Service_Delicious_PostList
     */
    public function getUserPosts($user, $count = null, $tag = null)
    {
        $parms = array();
        if ($count) {
            $parms['count'] = $count;
        }

        $path = sprintf(self::JSON_POSTS, $user, $tag);
        $res = $this->makeRequest($path, $parms, 'json');

        return new Zend_Service_Delicious_PostList($this, $res);
    }

    /**
     * Get tags of a user
     *
     * Returned array has tags as keys and number of posts as values
     *
     * @param  string $user    Owner of the posts
     * @param  int    $atleast Include only tags for which there are at least ### number of posts
     * @param  int    $count   Number of tags to get (default all)
     * @param  string $sort    Order of returned tags ('alpha' || 'count')
     * @return array
     */
    public function getUserTags($user, $atleast = null, $count = null, $sort = 'alpha')
    {
        $parms = array();
        if ($atleast) {
            $parms['atleast'] = $atleast;
        }
        if ($count) {
            $parms['count'] = $count;
        }
        if ($sort) {
            $parms['sort'] = $sort;
        }

        $path = sprintf(self::JSON_TAGS, $user);

        return $this->makeRequest($path, $parms, 'json');
    }

    /**
     * Get network of a user
     *
     * @param  string $user Owner of the network
     * @return array
     */
    public function getUserNetwork($user)
    {
        $path = sprintf(self::JSON_NETWORK, $user);
        return $this->makeRequest($path, array(), 'json');
    }

    /**
     * Get fans of a user
     *
     * @param  string $user Owner of the fans
     * @return array
     */
    public function getUserFans($user)
    {
        $path = sprintf(self::JSON_FANS, $user);
        return $this->makeRequest($path, array(), 'json');
    }

    /**
     * Get details on a particular bookmarked URL
     *
     * Returned array contains four elements:
     *  - hash - md5 hash of URL
     *  - top_tags - array of tags and their respective usage counts
     *  - url - URL for which details were returned
     *  - total_posts - number of users that have bookmarked URL
     *
     * If URL hasen't been bookmarked null is returned.
     *
     * @param  string $url URL for which to get details
     * @return array
     */
    public function getUrlDetails($url)
    {
        $parms = array('hash' => md5($url));

        $res = $this->makeRequest(self::JSON_URL, $parms, 'json');

        if(isset($res[0])) {
            return $res[0];
        } else {
            return null;
        }
    }

    /**
     * Handles all GET requests to a web service
     *
     * @param   string $path  Path
     * @param   array  $parms Array of GET parameters
     * @param   string $type  Type of a request ("xml"|"json")
     * @return  mixed  decoded response from web service
     * @throws  Zend_Service_Delicious_Exception
     */
    public function makeRequest($path, array $parms = array(), $type = 'xml')
    {
        // if previous request was made less then 1 sec ago
        // wait until we can make a new request
        $timeDiff = microtime(true) - self::$_lastRequestTime;
        if ($timeDiff < 1) {
            usleep((1 - $timeDiff) * 1000000);
        }

        $this->_rest->getHttpClient()->setAuth($this->_authUname, $this->_authPass);

        switch ($type) {
            case 'xml':
                $this->_rest->setUri(self::API_URI);
                break;
            case 'json':
                $parms['raw'] = true;
                $this->_rest->setUri(self::JSON_URI);
                break;
            default:
                /**
                 * @see Zend_Service_Delicious_Exception
                 */
                require_once 'Zend/Service/Delicious/Exception.php';
                throw new Zend_Service_Delicious_Exception('Unknown request type');
        }

        self::$_lastRequestTime = microtime(true);
        $response = $this->_rest->restGet($path, $parms);

        if (!$response->isSuccessful()) {
            /**
             * @see Zend_Service_Delicious_Exception
             */
            require_once 'Zend/Service/Delicious/Exception.php';
            throw new Zend_Service_Delicious_Exception("Http client reported an error: '{$response->getMessage()}'");
        }

        $responseBody = $response->getBody();

        switch ($type) {
            case 'xml':
                $dom = new DOMDocument() ;

                if (!@$dom->loadXML($responseBody)) {
                    /**
                     * @see Zend_Service_Delicious_Exception
                     */
                    require_once 'Zend/Service/Delicious/Exception.php';
                    throw new Zend_Service_Delicious_Exception('XML Error');
                }

                return $dom;
            case 'json':
                return Zend_Json_Decoder::decode($responseBody);
        }
    }

    /**
     * Transform XML string to array
     *
     * @param   DOMDocument $response
     * @param   string      $root     Name of root tag
     * @param   string      $child    Name of children tags
     * @param   string      $attKey   Attribute of child tag to be used as a key
     * @param   string      $attValue Attribute of child tag to be used as a value
     * @return  array
     * @throws  Zend_Service_Delicious_Exception
     */
    private static function _xmlResponseToArray(DOMDocument $response, $root, $child, $attKey, $attValue)
    {
        $rootNode = $response->documentElement;
        $arrOut = array();

        if ($rootNode->nodeName == $root) {
            $childNodes = $rootNode->childNodes;

            for ($i = 0; $i < $childNodes->length; $i++) {
                $currentNode = $childNodes->item($i);
                if ($currentNode->nodeName == $child) {
                    $arrOut[$currentNode->getAttribute($attKey)] = $currentNode->getAttribute($attValue);
                }
            }
        } else {
            /**
             * @see Zend_Service_Delicious_Exception
             */
            require_once 'Zend/Service/Delicious/Exception.php';
            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
        }

        return $arrOut;
    }

    /**
     * Constructs Zend_Service_Delicious_PostList from XML response
     *
     * @param   DOMDocument $response
     * @return  Zend_Service_Delicious_PostList
     * @throws  Zend_Service_Delicious_Exception
     */
    private function _parseXmlPostList(DOMDocument $response)
    {
        $rootNode = $response->documentElement;

        if ($rootNode->nodeName == 'posts') {
            return new Zend_Service_Delicious_PostList($this, $rootNode->childNodes);
        } else {
            /**
             * @see Zend_Service_Delicious_Exception
             */
            require_once 'Zend/Service/Delicious/Exception.php';
            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
        }
    }

    /**
     * Evaluates XML response
     *
     * @param   DOMDocument $response
     * @return  void
     * @throws  Zend_Service_Delicious_Exception
     */
    private static function _evalXmlResult(DOMDocument $response)
    {
        $rootNode = $response->documentElement;

        if ($rootNode && $rootNode->nodeName == 'result') {

            if ($rootNode->hasAttribute('code')) {
                $strResponse = $rootNode->getAttribute('code');
            } else {
                $strResponse = $rootNode->nodeValue;
            }

            if ($strResponse != 'done' && $strResponse != 'ok') {
                /**
                 * @see Zend_Service_Delicious_Exception
                 */
                require_once 'Zend/Service/Delicious/Exception.php';
                throw new Zend_Service_Delicious_Exception("del.icio.us web service: '{$strResponse}'");
            }
        } else {
            /**
             * @see Zend_Service_Delicious_Exception
             */
            require_once 'Zend/Service/Delicious/Exception.php';
            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
        }
    }
}


text:
<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage StrikeIron
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: StrikeIron.php 23775 2011-03-01 17:25:24Z ralph $
 */

/**
 * This class allows StrikeIron authentication credentials to be specified
 * in one place and provides a factory for returning instances of different
 * StrikeIron service classes.
 *
 * @category   Zend
 * @package    Zend_Service
 * @subpackage StrikeIron
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Service_StrikeIron
{
    /**
     * Options to pass to Zend_Service_StrikeIron_Base constructor
     * @param array
     */
    protected $_options;

    /**
     * Class constructor
     *
     * @param array  $options  Options to pass to Zend_Service_StrikeIron_Base constructor
     */
    public function __construct($options = array())
    {
        $this->_options = $options;
    }

    /**
     * Factory method to return a preconfigured Zend_Service_StrikeIron_*
     * instance.
     *
     * @param  null|string  $options  Service options
     * @return object       Zend_Service_StrikeIron_* instance
     * @throws Zend_Service_StrikeIron_Exception
     */
    public function getService($options = array())
    {
        $class = isset($options['class']) ? $options['class'] : 'Base';
        unset($options['class']);

        if (strpos($class, '_') === false) {
            $class = "Zend_Service_StrikeIron_{$class}";
        }

        try {
            if (!class_exists($class)) {
                require_once 'Zend/Loader.php';
                @Zend_Loader::loadClass($class);
            }
            if (!class_exists($class, false)) {
                throw new Exception('Class file not found');
            }
        } catch (Exception $e) {
            $msg = "Service '$class' could not be loaded: " . $e->getMessage();
            /**
             * @see Zend_Service_StrikeIron_Exception
             */
            require_once 'Zend/Service/StrikeIron/Exception.php';
            throw new Zend_Service_StrikeIron_Exception($msg, $e->getCode(), $e);
        }

        // instantiate and return the service
        $service = new $class(array_merge($this->_options, $options));
        return $service;
    }

}