<?php

/**
 * A simple interface to Google Search API
 * Author: fbparis@gmail.com (http://fbparis.com/)
 * Please take a look on http://code.google.com/apis/ajaxsearch/documentation/#fonje before using this class
 * Also read this: http://code.google.com/apis/ajaxsearch/documentation/reference.html#_intro_fonje
 */

class GoogleSearch {
    const 
webSearchURL 'http://ajax.googleapis.com/ajax/services/search/web';
    const 
localSearchURL 'http://ajax.googleapis.com/ajax/services/search/local';
    const 
videoSearchURL 'http://ajax.googleapis.com/ajax/services/search/video';
    const 
blogSearchURL 'http://ajax.googleapis.com/ajax/services/search/blogs';
    const 
newsSearchURL 'http://ajax.googleapis.com/ajax/services/search/news';
    const 
bookSearchURL 'http://ajax.googleapis.com/ajax/services/search/books';
    const 
imageSearchURL 'http://ajax.googleapis.com/ajax/services/search/images';
    const 
patentSearchURL 'http://ajax.googleapis.com/ajax/services/search/patent';
    
    
/**
     * May be usefull :)
     * Apply for a key here: http://code.google.com/apis/ajaxsearch/signup.html
     */
    
public $google_api_key ''
    
    public 
$lastUrl ''// last accessed url
    
public $lastResponseHeaders = array(); // last HTTP response headers
    
public $lastResponseCode 0// last HTTP response code
    
public $lastResponse ''// last response, the raw version
    
    
public $responseStatus 0// last response status sent by google api
    
public $responseDetails ''// last response details sent by google api
    
public $cursor null// cursor returned by the google api
    
    
public $lang ''// Restricts results to the given language, given by an ISO 639-1 code
    
public $version '1.0'// Google Search API version
    
public $user_ip ''// This propertie supplies the IP address of the end-user on whose behalf the request is being made (optional)
    
public $rsz 4// This argument supplies the number of results that the application would like to recieve. Values can be any integer between 1 and 8
    
public $referer ''// "Applications MUST always include a valid and accurate http referer header in their requests" says Google :)
        
    
protected $host '';
    
    
/**
     * Constructor
     * Lang parameter restricts results to the given language, given by an ISO 639-1 code
     */
    
function __construct($lang='') {
        
$this->context stream_context_create(stream_context_get_options(stream_context_get_default()));
        
$this->http_option('max_redirects',1);
        if (
$lang$this->lang $lang;
    }
        
    
/**
     * You can use this method to get or set some http context options (see http://php.net/manual/en/context.http.php)
     * For example, to set the user agent to "Mozilla/5" call $object->http_option('user_agent','Mozilla/5')
     * If you must set non http options (ie: socket), you can use directly the stream_context_get_options() function with $object->context as context
     */
    
public function http_option($key,$value=null) {
        if (
$value === null) { // return the current value for this key
            
$options stream_context_get_options($this->context);
            return @
$options['http'][$key] ? $options['http'][$key] : '';
        } else { 
// set the option, return false if failed
            
return stream_context_set_option($this->context,'http',$key,$value);
        }
    }
            
    
/**
     * Return results for a web search query
     */
    
public function web($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        if (
$this->lang && !array_key_exists('lr',$parameters)) $parameters['lr'] = "lang_$this->lang";
        
$this->host self::webSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a local search query
     */
    
public function local($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::localSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a video search query
     */
    
public function video($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::videoSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a blog search query
     */
    
public function blog($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::blogSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a news search query
     */
    
public function news($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::newsSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a book search query
     */
    
public function book($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::bookSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a image search query
     */
    
public function image($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::imageSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Return results for a patent search query
     */
    
public function patent($q,$parameters=array()) {
        
$parameters['q'] = trim($q);
        
$this->host self::patentSearchURL;
        return 
$this->api_call($parameters);
    }
    
    
/**
     * Format query and return results
     */
    
protected function api_call($parameters) {
        
$this->http_option('header',$this->referer "Referer: $this->referer'');
        if (
$this->version$parameters['v'] = $this->version;
        if (
$this->lang$parameters['hl'] = $this->lang;
        if (
$this->google_api_key$parameters['key'] = $this->google_api_key;
        if (
$this->user_ip$parameters['user_ip'] = $this->user_ip;
        if (
$this->rsz$parameters['rsz'] = $this->rsz;
        
$r json_decode($this->http(sprintf('%s?%s',$this->host,http_build_query($parameters)),'GET'));
        
$this->http_option('header','');
        
$this->responseStatus is_object($r) && property_exists($r,'responseStatus') ? $r->responseStatus 0;
        
$this->responseDetails is_object($r) && property_exists($r,'responseDetails') ? $r->responseDetails '';
        
$this->cursor is_object($r) && property_exists($r,'responseData') && is_object($r->responseData) && property_exists($r->responseData,'cursor')? $r->responseData->cursor null;
        return 
is_object($r) && property_exists($r,'responseData') && is_object($r->responseData) && property_exists($r->responseData,'results') ? $r->responseData->results : array();
    }

    
/**
     * Make an HTTP request
     * Infinite loops of redirections are not handled...
     * Last URL opened will be notified in $object->lastUrl
     * Last HTTP Response Code will be notified in $object->lastResponseCode (can be 0 if the request has failed)
     * Last HTTP Response Headers will be notified in $object->lastResponseHeaders (see http://php.net/manual/en/reserved.variables.httpresponseheader.php)
     * You can access the last raw response via $object->lastResponse
     */ 
    
protected function http($url,$method,$postfields='') {
        
$this->lastResponseCode 0;
        
$this->http_option('method',$method);
        
$this->http_option('content',$postfields);
        
$response = @file_get_contents($url,false,$this->context);
        
$this->lastUrl $url;
        
$this->lastResponseHeaders $http_response_header;
        
$this->lastResponse $response;
        if (
is_array($this->lastResponseHeaders)) {
            foreach (
$this->lastResponseHeaders as $i=>$header) {
                if (
$i == 0$this->lastResponseCode preg_match('#^HTTP/[0-9.]+ ([0-9]+)#s',$header,$m) ? intval($m[1]) : 0;
                elseif (
preg_match('#^Location: (.*)$#s',$header,$m)) return $this->http(trim($m[1]),'GET');
            }
        } else 
$this->lastResponseHeaders = array();
        return 
$response;
    }
}

?>