View source
<?php
if (!defined('GOOGLE_MINI_MAX_RESULTS')) {
define('GOOGLE_MINI_MAX_RESULTS', 1000);
}
class GoogleMini {
private $_metaDataFilters = array();
public $baseUrl = '';
public $frontEnd = '';
public $collection = '';
protected $_queryParts;
public function __construct($debug = FALSE, $debug_callback = NULL) {
if ($debug) {
$this->debug = TRUE;
if ($debug_callback && function_exists($debug_callback)) {
$this->debug_callback = $debug_callback;
}
}
}
function log($message = NULL) {
if ($this->debug_callback) {
$callback = $this->debug_callback;
call_user_func($callback, $message);
}
error_log($message);
}
public function setQueryPart($key, $value) {
$this->_queryParts[$key] = $value;
}
public function getQueryPart($key) {
if ($this->_queryParts[$key]) {
return $this->_queryParts[$key];
}
return false;
}
public function addMetaDataFilter($key, $values, $type = 'partialfields', $join = 'OR') {
if (!in_array($type, array(
'partialfields',
'requiredfields',
))) {
throw new GoogleMiniCriteriaException("You must provide a type of either partialfields or requiredfields", '-99');
}
if (is_array($values)) {
$this->_metaDataFilters[$type][$key] = new stdClass();
$this->_metaDataFilters[$type][$key]->type = $join;
foreach ($values as $k => $value) {
$this->_metaDataFilters[$type][$key]->values[] = urlencode($value);
}
}
else {
$this->_metaDataFilters[$type][$key]->type = $join;
$this->_metaDataFilters[$type][$key]->values = array(
urlencode($values),
);
}
}
public function setLanguageFilter($languages = NULL) {
if ($languages) {
if (is_array($languages)) {
$this
->setQueryPart("lr", implode('|', $languages));
}
else {
$this
->setQueryPart("lr", $languages);
}
return TRUE;
}
return FALSE;
}
public function setDateFilter($date_before, $date_after) {
if ($this->_queryParts['q']) {
$this->_queryParts['q'] .= "%20daterange:{$date_before}..{$date_after}";
}
else {
$this
->setQueryPart('q', "daterange:{$date_before}..{$date_after}");
}
}
public function setDomainRestriction($domain) {
if ($this->_queryParts['q']) {
$this->_queryParts['q'] .= "%20site:{$domain}";
}
else {
$this
->setQueryPart('q', "site:" . urlencode($domain));
}
}
public function setDateSort($dir = "D", $mode = 'S') {
if ($dir != 'A' && $dir != 'D') {
throw new GoogleMiniCriteriaException(sprintf("The Sort direction provided is incorrect. Got %s, needs to be A or D", htmlentities($dir)), E_WARNING);
}
if ($mode != 'S' && $mode != 'R') {
throw new GoogleMiniCriteriaException(sprintf("The Sort mode provided is incorrect. Got %s, needs to be S or R", htmlentities($mode)), E_WARNING);
}
$this
->setQueryPart('sort', "date:{$dir}:{$mode}:d1");
return true;
}
public function setKeywords($keys) {
if ($this->_queryParts['q']) {
$this->_queryParts['q'] .= "%20" . urlencode($keys);
}
else {
$this
->setQueryPart('q', urlencode($keys));
}
}
public function setMetaDataRequested($fields = NULL) {
if (is_array($fields)) {
$this
->setQueryPart('getfields', implode('.', $fields));
}
else {
$this
->setQueryPart('getfields', $fields);
}
}
public function setPageAndResultsPerPage($page = 0, $results = 10) {
$end = $page * $results + $results;
if ($end > GOOGLE_MINI_MAX_RESULTS) {
throw new GoogleMiniCriteriaException("You cannot get more than " . GOOGLE_MINI_MAX_RESULTS . " results per page, requested {$end}", 2);
}
$this
->setQueryPart('start', $page * $results);
$this
->setQueryPart('num', $results);
return true;
}
public function setOutputEncoding($enc) {
$this
->setQueryPart('oe', $enc);
}
public function setInputEncoding($enc) {
$this
->setQueryPart('ie', $enc);
}
public function buildQuery() {
if (!$this->baseUrl || !$this->collection) {
throw new GoogleMiniQueryException("Required variables (baseUrl or collection) missing", E_WARNING);
}
if (count($this->_metaDataFilters)) {
foreach ($this->_metaDataFilters as $type => $fields) {
$_metafilter = '';
foreach ($fields as $field => $mdf) {
if ($mdf->type == "ANDNEG") {
foreach ($mdf->values as $value) {
$metafilter .= '-' . $field . ':' . $value . '.';
}
}
elseif ($mdf->type == 'OR' || $mdf->type == 'OROR') {
$vals = array();
foreach ($mdf->values as $v) {
$vals[] = $field . ':' . $v;
}
if ($mdf->type == 'OROR') {
$metafilter .= '(' . join("|", $vals) . ")|";
}
else {
$metafilter .= '(' . join("|", $vals) . ").";
}
}
else {
foreach ($mdf->values as $value) {
$metafilter .= $field . ':' . $value . '.';
}
}
}
$metafilter = substr($metafilter, 0, -1);
$this
->setQueryPart($type, $metafilter);
}
}
$this
->setQueryPart('output', 'xml_no_dtd');
$query = $this->baseUrl;
$query .= "?site=" . $this->collection;
if ($this->debug) {
$this
->log('Building Query');
$this
->log(var_export($this->_queryParts, 1));
}
foreach ($this->_queryParts as $label => $value) {
$query .= "&{$label}={$value}";
}
$this->_query = $query;
if ($this->debug) {
$this
->log($query);
}
return $query;
}
public function query($iteratorClass = 'GoogleMiniResultIterator') {
$query = $this
->buildQuery();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $query);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
if ($timeout = variable_get('google_appliance_timeout', FALSE)) {
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
}
$resultXML = curl_exec($ch);
if ($this->debug) {
$this
->log('Made cURL request to ' . $query);
}
if (!$resultXML) {
if ($this->debug) {
$this
->log('cURL error #' . curl_errno($ch) . ': ' . curl_error($ch));
}
throw new GoogleMiniResultException('There was a cURL error while connecting with the Google device.');
return FALSE;
}
return self::resultFactory($resultXML, $iteratorClass);
}
function resultFactory($resultXML, $className = 'GoogleMiniResultIterator') {
$results = array();
libxml_use_internal_errors(TRUE);
if (!($payload = simplexml_load_string($resultXML))) {
$errors = array();
foreach (libxml_get_errors() as $error) {
$errors[] = $error->message;
}
$errors = join(', ', $errors);
throw new GoogleMiniResultException('There was an error parsing the result XML: ' . $errors);
return FALSE;
}
$totalResults = $payload->RES->M;
if ($totalResults == 0) {
if (!$payload->GM) {
throw new GoogleMiniResultException("No Results found", '1');
}
}
else {
foreach ($payload
->xpath('//R') as $res) {
$results[] = $res;
}
}
$iterator = new $className($results);
$iterator->payload = $payload;
$iterator->time = $payload->TM;
$iterator->totalResults = $totalResults;
return $iterator;
}
}
class GoogleResult extends SimpleXMLIterator {
}
class GoogleMiniResultIterator extends ArrayIterator {
public $time;
public $payload;
public $totalResults;
function current() {
$result = parent::current();
return new GoogleMiniResult($result);
}
function __get($key) {
return $this->payload->{$key};
}
function getKeyMatches() {
$output = array();
if ($this->GM) {
foreach ($this->GM as $match) {
$output[(string) $match->GL] = (string) $match->GD;
}
}
return $output;
}
function getSynonyms() {
$output = array();
if ($this->Synonyms) {
foreach ($this->Synonyms
->children() as $child) {
$output[] = (string) $child['q'];
}
}
return $output;
}
}
class GoogleMiniResult {
var $metaData;
function __construct($result) {
$this->result = $result;
}
function __get($key) {
return $this->result->{$key};
}
function getMetaData($key) {
if (!$this->metaData) {
$this
->buildMetaData();
}
return $this->metaData[$key];
}
function buildMetaData() {
foreach ($this->result->MT as $metaTag) {
$name = $metaTag['N'];
$value = $metaTag['V'];
$this->metaData[(string) $name] = (string) $value;
}
}
}
class GoogleMiniQueryException extends GoogleMiniException {
}
class GoogleMiniCriteriaException extends GoogleMiniException {
}
class GoogleMiniResultException extends GoogleMiniException {
var $log_messages = array();
}
class GoogleMiniException extends Exception {
function __construct($message, $code = null) {
parent::__construct($message, $code);
$this->userMessage = GoogleMiniException::getUserMessage($code);
if (!$this->userMessage) {
$this->userMessage = $message;
}
}
function getErrorCodes() {
static $error_codes;
if (!$error_codes) {
$error_codes = array(
'-100' => 'We apologize, but the connection to our search engine appears to be down at the moment, please try again later.',
'-99' => 'We apologize, but your search cannot be completed at this time, please try again later.',
'1' => 'No results were found that matched your criteria. Please try broadening your search.',
'2' => 'Sorry, but our search does not return more than 1,000 records, please refine your criteria.',
);
}
return $error_codes;
}
function getUserMessage($code) {
$error_codes = $this
->getErrorCodes();
return $error_codes[$code];
}
}