<?php
/**
* Class Yandex
*
* yandex search class
*
* @author Anton Shevchuk <AntonShevchuk@gmail.com>
* @link http://anton.shevchuk.name
* @access public
* @package Yandex.class.php
* @created Thu Aug 14 12:12:54 EEST 2008
*/
class Yandex
{
/**
* Response
*
* @var SimpleXML
*/
public $result;
/**
* Query
*
* @var string
*/
protected $query;
/**
* Number of page
*
* @var integer
*/
protected $page = 0;
/**
* Number of results per page
*
* @var integer
*/
protected $limit = 10;
/**
* Options of search
*
* @var array
*/
protected $options = array(
'sortby' => null , // http://help.yandex.ru/xml/?id=316625#sort <rlv> <tm>
'maxpassages' => null , // from 2 to 5
'groupings' => null , // http://help.yandex.ru/xml/?id=316625#group <d> <geo> <cat> <>
'max-title-length' => null , //
'max-headline-length' => null , //
'max-passage-length' => null , //
'max-text-length' => null , //
);
/**
* Error code
*
* @var integer
*/
public $error = null;
/**
* Errors in response
*
* @var array
*/
// TODO: add all errors code
protected $errors = array(
1 => 'Синтаксическая ошибка — ошибка в языке запросов',
2 => 'Задан пустой поисковый запрос — элемент query не содержит данных',
8 => 'Зона не проиндексирована — обратите внимание на корректность параметров зонно-атрибутивного поиска',
9 => 'Атрибут не проиндексирован — обратите внимание на корректность параметров зонно-атрибутивного поиска',
10 => 'Атрибут и элемент не совместимы — обратите внимание на корректность параметров зонно-атрибутивного поиска',
12 => 'Результат предыдущего запроса уже удален — задайте запрос повторно, не ссылаясь на идентификатор предыдущего запроса',
15 => 'Найдётся всё. Со временем',
18 => 'Ошибка в XML-запросе — проверьте валидность отправляемого XML и корректность параметров',
19 => 'Заданы несовместимые параметры запроса — проверьте корректность группировочных атрибутов',
20 => 'Неизвестная ошибка — при повторяемости ошибки обратитесь к разработчикам с описанием проблемы',
);
/**
* Constructor of Yandex
*
* @access public
*/
function __construct()
{
}
/**
* Destructor of Yandex
*
* @access public
*/
function __destruct()
{
}
/**
* query
*
* @access public
* @param string $query
* @return Yandex
*/
public function query($query)
{
$this->query = $query;
return $this;
}
/**
* getQuery
*
* @access public
* @return string
*/
public function getQuery()
{
return $this->query;
}
/**
* page
*
* @access public
* @param integer $page
* @return Yandex
*/
public function page($page)
{
$this->page = $page;
return $this;
}
/**
* getPage
*
* @access public
* @return integer
*/
public function getPage()
{
return $this->page;
}
/**
* limit
*
* @access public
* @param integer $limit
* @return Yandex
*/
public function limit($limit)
{
$this->limit = $limit;
return $this;
}
/**
* getLimit
*
* @access public
* @return integer
*/
public function getLimit()
{
return $this->limit;
}
/**
* set
*
* @access public
* @param string $option
* @param mixed $value
* @return Yandex
*/
public function set($option, $value = null)
{
$this->options[$option] = $value;
return $this;
}
/**
* request
*
* send request
*
* @access public
* @return Yandex
*/
public function request()
{
if (empty($this->query)) {
throw new Exception('Query is empty');
}
$request = '<?xml version="1.0" encoding="utf-8"?>
<request>';
// add query to request
$request .= '<query><![CDATA['.$this->query.']]></query>';
if ($this->page) {
$request .= '<page>'.$this->page.'</page>';
}
$request .= '<groupings>
<groupby attr="" mode="flat" groups-on-page="'.$this->limit.'" docs-in-group="1" curcateg="-1" />
</groupings>';
// TODO: add groupings and sortby realisation
/*
<sortby order="descending" priority="no">rlv</sortby>
<groupings>
<groupby attr="d" mode="deep" groups-on-page="10" docs-in-group="1" curcateg="-1"/>
</groupings>
<groupings>
<groupby attr="" mode="flat" groups-on-page="10" docs-in-group="1" />
</groupings>
*/
if ($this->options['maxpassages']) {
$request .= '<maxpassages>'.$this->options['maxpassages'].'</maxpassages>';
}
if ($this->options['max-title-length']) {
$request .= '<max-title-length>'.$this->options['max-title-length'].'</max-title-length>';
}
if ($this->options['max-headline-length']) {
$request .= '<max-headline-length>'.$this->options['max-headline-length'].'</max-headline-length>';
}
if ($this->options['max-passage-length']) {
$request .= '<max-passage-length>'.$this->options['max-passage-length'].'</max-passage-length>';
}
if ($this->options['max-text-length']) {
$request .= '<max-text-length>'.$this->options['max-text-length'].'</max-text-length>';
}
$request .= '</request>';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://xmlsearch.yandex.ru/xmlsearch");
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: application/xml"));
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Accept: application/xml"));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_POST, TRUE);
$data = curl_exec($ch);
$this->result = new SimpleXMLElement($data);
$this->checkErrors();
return $this;
}
/**
* checkErrors
*
* check response errors
*
* @author dark
* @class
* @access public
* @param type $param param_descr
* @return rettype return
*/
protected function checkErrors()
{
// switch statement for $this->result->response->error
switch (true) {
case isset($this->result->response->error) &&
($error = $this->result->response->error->attributes()->code || $this->result->response->error->attributes()->code === 0):
$error = (int)$error;
if (isset($this->errors[$error])) {
$this->error = $this->errors[$error];
} else {
$this->error = $this->result->response->error;
}
break;
case isset($this->result->response->error) && !empty($this->result->response->error):
$this->error = $this->result->response->error;
break;
default:
$this->error = null;
break;
}
}
/**
* total
*
* get total results
*
* @access public
* @return integer
*/
public function total()
{
// FIXME: need fix?
if (empty($this->total)) {
$res = $this->result->xpath('response/found[attribute::priority="all"]');
$this->total = (int)$res[0];
}
return $this->total;
}
/**
* pages
*
* get total pages
*
* @access public
* @param type $param param_descr
* @return rettype return
*/
public function pages()
{
if (empty($this->pages))
$this->pages = ceil($this->total() / $this->limit);
return $this->pages;
}
/**
* pageBar
*
* return pagebar
*
* @access public
* @return rettype return
*/
public function pageBar()
{
// FIXME: not good
$pages = $this->pages();
if ($pages < 10) {
$pagebar = array_fill(0, $pages, array('type'=>'link', 'text'=>'%d'));
} elseif ($pages >= 10 && $this->page < 9) {
$pagebar = array_fill(0, 10, array('type'=>'link', 'text'=>'%d'));
$pagebar[$this->page] = array('type'=>'current', 'text'=>'<b>%d</b>');
} elseif ($pages >= 10 && $this->page >= 9) {
$pagebar = array_fill(0, 2, array('type'=>'link', 'text'=>'%d'));
$pagebar[] = array('type'=>'text', 'text'=>'..');
$pagebar += array_fill($this->page-2, 2, array('type'=>'link', 'text'=>'%d'));
if ($pages > ($this->page+2))
$pagebar += array_fill($this->page, 2, array('type'=>'link', 'text'=>'%d'));
$pagebar[$this->page] = array('type'=>'current', 'text'=>'<b>%d</b>');
}
return $pagebar;
}
/**
* highlight
*
* highlight text
*
* @access public
* @param SimpleXML $text
* @return rettype return
*/
static function highlight($text)
{
// FIXME: very strangely method
$xml = $text->asXML();
$xml = str_replace('<hlword priority="strict">', '<b>', $xml);
$xml = str_replace('</hlword>', '</b>', $xml);
$xml = strip_tags($xml, '<b>');
echo $xml;
}
}