Services_Digg
[ class tree: Services_Digg ] [ index: Services_Digg ] [ all elements ]

Source for file Request.php

Documentation is available at Request.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * A class for running parallel requests to the API
  7.  *
  8.  * PHP version 5.1.0+
  9.  *
  10.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  11.  * that is available through the world-wide-web at the following URI:
  12.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  13.  * the PHP License and are unable to obtain it through the web, please
  14.  * send a note to license@php.net so we can mail you a copy immediately.
  15.  *
  16.  * @category    Services
  17.  * @package     Services_Digg
  18.  * @author      Joe Stump <joe@joestump.net>
  19.  * @copyright   1997-2007 The PHP Group
  20.  * @license     http://www.php.net/license/3_0.txt  PHP License 3.0
  21.  * @version     CVS: $Id:$
  22.  * @link        http://pear.php.net/package/Services_Digg
  23.  */
  24.  
  25. /**
  26.  * A class for running parallel requests to the API
  27.  *  
  28.  * This class allows you to send parallel asynchronous requests to the Digg API
  29.  * without locking your script waiting for those requests to return.
  30.  *
  31.  * <code>
  32.  * <?php
  33.  * 
  34.  * // Make sure your keys are valid PHP variable names so it doesn't throw
  35.  * // an error when trying to access the results later on.
  36.  * $endPoints = array(
  37.  *     'popular' => 'http://services.digg.com/stories/popular',
  38.  *     'errors'  => 'http://services.digg.com/errors',
  39.  *     'topics'  => 'http://services.digg.com/topics'
  40.  * );
  41.  *
  42.  * // Start the requests. You'll want to run this at the very top of your
  43.  * // script so that the parallel requests start working immediately.
  44.  * $req = new Services_Digg_Request($endPoints);
  45.  * 
  46.  * // The calls are asynchronous and ran in parallel so keep on working on
  47.  * // other stuff while that runs in the background.
  48.  *
  49.  * // Now I need the popular stories
  50.  * foreach ($req->popular->stories as $story) {
  51.  *     echo '<h2>' . $story->title . '</h2>' . "\n";
  52.  * }
  53.  *
  54.  * ?>
  55.  * </code>
  56.  *
  57.  * Keep in mind that the requests to the API run both in parallel and
  58.  * asynchronously in the background. This means that calls to the API are no
  59.  * longer blocking and only take as long as the slowest API request.
  60.  *  
  61.  * @category    Services
  62.  * @package     Services_Digg
  63.  * @author      Joe Stump <joe@joestump.net>
  64.  * @abstract
  65.  */
  66. {
  67.     /**
  68.      * A socket for each API endpoint
  69.      *
  70.      * @access      private
  71.      * @var         array       $sockets 
  72.      */
  73.     private $sockets = array();
  74.  
  75.     /**
  76.      * Results from each API endpoint
  77.      *
  78.      * @access      private
  79.      * @var         array       $results 
  80.      * @see         Services_Digg_Request::__get()
  81.      */
  82.     private $results = array();
  83.  
  84.     /**
  85.      * The actual calls that are made
  86.      *
  87.      * @access      private
  88.      * @var         array       $urls 
  89.      */
  90.     private $urls = array();
  91.  
  92.     /**
  93.      * Constructor
  94.      *
  95.      * Create an instance of parallel asynchronous requests to the Digg API by
  96.      * passing an array of endpoints keyed by a valid PHP variable name.
  97.      *
  98.      * @access      public
  99.      * @param       array       $urls       Array of endpoints keyed by name
  100.      * @return      void 
  101.      */
  102.     public function __construct($urls)
  103.     {
  104.         foreach ($urls as $name => $endpoint{
  105.             $parts parse_url($endpoint);
  106.             if (!isset($parts['port'])) {
  107.                 $parts['port'= 80;
  108.             }
  109.  
  110.             $this->initialize($name$parts);
  111.         }
  112.     }
  113.  
  114.     /**
  115.      * Initialize a request to the API
  116.      *
  117.      * Sets up the basic HTTP request so that the API can start churning along
  118.      * until we need the actual data. Data is read down and returned via the
  119.      * getter.
  120.      *
  121.      * @access      private
  122.      * @param       string      $name       Name of request
  123.      * @param       array       $h          Host/port, etc. from parse_url()
  124.      * @return      void 
  125.      * @throws      Services_Digg_Exception
  126.      * @see         Services_Digg_Request::__construct()
  127.      * @see         Services_Digg_Request::__get()
  128.      */
  129.     private function initialize($name$h)
  130.     {
  131.         $this->sockets[$namesocket_create(AF_INETSOCK_STREAMSOL_TCP);
  132.         $res socket_connect($this->sockets[$name]$h['host']$h['port']);
  133.         if ($res === false{
  134.             throw new Services_Digg_Exception(socket_strerror()socket_last_error());
  135.         
  136.  
  137.  
  138.         $request $h['path'];
  139.         if (isset($h['query'])) {
  140.             $request .= '?' $h['query'];
  141.         }
  142.         
  143.         $init = array('GET ' $request ' HTTP/1.1',
  144.                       'Host: ' $h['host'],
  145.                       'User-Agent: Services_Digg_Request (' Services_Digg::$appKey ')',
  146.                       'Connection: Close');
  147.  
  148.         foreach ($init as $header{
  149.             socket_write($this->sockets[$name]$header "\r\n");
  150.         }
  151.  
  152.         socket_write($this->sockets[$name]"\r\n");
  153.         $this->results[$name= null;
  154.         $this->urls[$name'http://' $h['host'':' $h['port'$request;
  155.     }
  156.  
  157.     /**
  158.      * Read results back in via getter
  159.      *
  160.      * When you create your parallel request you need to add keys to the array
  161.      * of endpoints, which you'll reference with the getter. If the result has
  162.      * not been parsed yet it will be read from the stream and then parsed.
  163.      *
  164.      * @access      public
  165.      * @param       string      $name       Name of request
  166.      * @return      mixed       The result object or an exception on error
  167.      */
  168.     public function __get($name)
  169.     {
  170.         if (!is_null($this->results[$name])) {
  171.             return $this->results[$name];
  172.         }
  173.  
  174.         $res $b '';
  175.         while ($b socket_read($this->sockets[$name]8096)) {
  176.             $res .= $b;
  177.         }
  178.         socket_close($this->sockets[$name]);
  179.  
  180.         // Responses can contain \r\n\r\n elsewhere after the headers so we
  181.         // shift off the headers and then implode again on \r\n\r\n to get the
  182.         // full response body.
  183.         $parts explode("\r\n\r\n"$res);
  184.         array_shift($parts);
  185.         $php implode("\r\n\r\n"$parts);
  186.  
  187.         try {
  188.             $response Services_Digg_Response::factory(
  189.                 'php'$php
  190.             );
  191.  
  192.             $this->results[$name$response->parse();
  193.         catch (Services_Digg_Response_Exception $e{
  194.             $this->results[$name= new Services_Digg_Exception($e->getMessage()$e->getCode()$this->urls[$name]$php);
  195.         }
  196.  
  197.         return $this->results[$name];
  198.     }
  199.  
  200.     /**
  201.      * Destructor
  202.      *
  203.      * Closes any sockets that might still be open at the end of the script or
  204.      * when the variable is overwritten.
  205.      *
  206.      * @access      public
  207.      * @return      void 
  208.      */
  209.     public function __destruct()
  210.     {
  211.         foreach ($this->sockets as $socket{
  212.             if (is_resource($socket)) {
  213.                 socket_close($socket);
  214.             }
  215.         }
  216.     }
  217.  
  218.     /**
  219.      * Builds a raw call to the API
  220.      *
  221.      * @access      public
  222.      * @param       string      $endPoint       API endpoint (e.g. /topics)
  223.      * @param       array       $params         GET parameters key/value pair
  224.      * @return      string      The RAW response with your API key, etc.
  225.      * @static
  226.      */
  227.     static public function buildCall($endPointarray $params = array())
  228.     {
  229.         $params['type''php';
  230.         $params['appkey'Services_Digg::$appKey;
  231.         $sets = array();
  232.         foreach ($params as $key => $val{
  233.             $sets[$key '=' $val;
  234.         }
  235.  
  236.         return Services_Digg::$uri $endPoint '?' . implode('&'$sets);
  237.     }
  238. }
  239.  
  240. ?>

Documentation generated on Tue, 04 Dec 2007 15:00:11 -0500 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.