<?php

//*************************************************************************
// base_web_api.php : implementation file
// Version : 4.0
// Date :  December 2013
// Author : Andre Dolenko
// Email :  bigfozzy@gmail.com
// Latest Version : http://x-datas.com/
//*************************************************************************

//////////////////////////////////////////////////// BasedWebPAI /////////////////////////////////////////////////////////////////////////
class CBaseWebAPI
{
    
///////////////////////////////////////////////////

    // имя сборщика
    
var $name null ;
    
// аббревиатура сборщика
    
var $abbreviature null ;
    
// запрашиваемый урл с параметрами
    
var $requested_url null ;

    
// путь для записи результатов
    
var $out_path="out/results.txt";

    
// пауза после удачного запроса
    
var $pause_per_request=1;
    
// пауза после наудачных запросов
    
var $pause_bad_request=5;

    
// использовать ли прокси при запросе
    
var $use_proxy=true;
    
// максимальное время запроса через прокси
    
var $proxy_timeout=10;
    
// максимальное число плохих запросов
    
var $max_num_bad=200;
    
// перестартовать после заданного числа пройденных страниц
    
var $num_restart_after=null;

    
// параметр - текущий запрос
    
var $current_query;
    
// дополнительный параметр - сайт
    
var $site="localhost";
    
// прокси через который было получение
    
var $proxy=null;

    
// промежуточные результаты 1
    
var $body;
    
// число обработанных запросов в данный запуск
    
var $queries_proceeded=1;
    
// число обработанных данных
    
var $pages_proceeded=0;
    
// число полученыых подданных
    
var $subdatas_received=0;
    
// время старта
    
var $start_time;
    
// время окончания
    
var $end_time=null;

    
///////////////////////////////////////////////////

    // конструктор        
    
function CBaseWebAPI($out_path,$pause_per_request,$pause_bad_request,$use_proxy,$proxy_timeout)
    {
        
// файл для записи выходных результатов
        
$this->out_path=$out_path;

        
// пауза между запросами
        
$this->pause_per_request=$pause_per_request;

        
// пауза если наш запрос был забанен или прокси не справился
        
$this->pause_bad_request=$pause_bad_request;

        
// использовать ли пркоси
        
$this->use_proxy=$use_proxy;

        
// максимальнео время работы через прокси
        
$this->proxy_timeout=$proxy_timeout;                

        
// инициализация
        
$this->init();
    }
        
    
// инициализация
    
protected function init()
    {      
    }

    
///////////////////////////////////////////////////

    // зададим прокси
    
protected function set_proxy($ch)
    {      
        
// зададим прокси в запрос
        
if ($this->use_proxy)
        {        
            
// получим прокси от поставщика проксей
            
global $proxies;
            
$this->proxy=$proxies->get_current_proxy();

            
// зададим прокси
            
curl_setopt($chCURLOPT_PROXY$this->proxy->get());

            
// таймаут (время за котрое прокси должно справится)
            
curl_setopt($chCURLOPT_TIMEOUT$this->proxy_timeout);

            
// лог
            
global $log;
            
$log->event_add(" [ ".$this->proxy->get()." ] ");
        }
    }    

    
// надо ли пропускать запрс
    
protected function is_skip_query($query)
    {      
        return 
false;
    }    

    
// выполним запрос
    
protected function init_query($query)
    {
        
// текущий запрос
        
$this->current_query=$query;

        
// API url                
        
$url=$this->requested_url.urlencode(iconv("windows-1251","utf-8//IGNORE",$this->current_query));        

        
// запрос
        
$ch curl_init();
        
curl_setopt($chCURLOPT_URL$url);
        
curl_setopt($chCURLOPT_RETURNTRANSFER1);
        
curl_setopt($chCURLOPT_REFERER$this->site);    
        
curl_setopt($chCURLOPT_HEADER0); 
        
curl_setopt($chCURLOPT_ENCODING"gzip");

        
// вернем подготовленный запрос
        
return $ch;
    }

    
// выполним запрос
    
protected function run_query($ch)
    {
        
// зададим прокси
        
$this->set_proxy($ch);

        
// выполниить запрос
        
$this->body curl_exec($ch);    

        
// убрать из запроса лишнее
        
$this->body=str_replace("\t","",$this->body);
        
$this->body=str_replace("\r","",$this->body);
        
$this->body=str_replace("\n","",$this->body);

        
// преобработать запрос
        
$this->pre_procced_results();
        return 
true;
    }

    
// загрузим следующую страницу данных для текущего запроса
    
protected function load_next_page($ch)
    {
        
// закроем запрос
        
if ($ch)
            
curl_close($ch);
        return 
false;
    }

    
// убрать из запроса лишнее
    
protected function pre_procced_results()
    {
    }

    
// проверить правильно ли прошел запрос
    
protected function is_query_good()
    {
        
$res = ($this->body=="")==0;    
        return 
$res;    
    }

    
// лог плохого запроса
    
protected function log_bad_query()
    {                
        
// событие статуса неудачи
        
global $log;
        if (
$this->body=="")
            
$log->event_add(" E ");
        else
            
$log->event_add(" B ");
    }

    
///////////////////////////////////////////////////

    // сделать запрос поисковых результатов через Google API
    
function get($query)
    {
        
// начало события
        
global $log;
        
$log->event_begin("$this->abbreviature : обрабатываем $query : ");        
    
        
// инициализируем запрос
        
$ch=$this->init_query($query);

        
// проверить управляющие события            
        
if ($this->check_controls_event()=="break")
        {
            
// останов
            
$log->event("Получена команда останова.");    
            die();
        }
        
// выполним запрос
        
$this->run_query($ch);

        
// начнем обработку запроса
        
while (true)
        {        
            
// цикл пока не достучимся - с заданной паузой
            
$num_bad=0;
            while ( !
$this->is_query_good() )
            {
                
// лог
                
$this->log_bad_query();

                
// прокси не сработал
                
if ($this->proxy)
                    
$this->proxy->report(0);

                
// пауза
                
sleep($this->pause_bad_request);

                
// условие выхода
                
$num_bad++;
                if (
$num_bad>$this->max_num_bad)
                {
                    
$event="Превышено число плохих запросов в ".__DIR__;
                    
$log->event_mail($this->name."(".__DIR__.")",$event);
                    
$log->event($event);
                die(
1);
                }

                
// проверить управляющие события            
                
if ($this->check_controls_event()=="break")
                {
                    
// останов
                    
$log->event("Получена команда останова.");    
                    die();
                }
                
// перезапрос
                
$this->run_query($ch);
            }
            
            
// прокси сработал
            
if ($this->proxy)
                
$this->proxy->report(1);

            
// пауза между запросами
            
sleep($this->pause_per_request);

            
// увеличим счетчик обработанных страниц
            
$this->pages_proceeded++;

            
// загрузим следующую страницу
            
if (!$this->load_next_page($ch))
                break;
        }
    
        
// отработали успешно
        
return true;
    }

    
///////////////////////////////////////////////////

    // сохранить обработанные поисковые результаты в файл 
    
function save()
    {    
        return 
0;
    }

    
// записать статистику текущего сбора
    
function write_stat()
    {
        
// лог
        
global $log;
        
$log->event("Запишем текущую статистику");

        global 
$proxies;global $queries;


        
// оформим статистику
        
$stat ="--------------------\n";
        
$stat.=$this->name."\n";
        
$stat.="Выходной файл = $this->out_path \n";
        
$stat.="Пройдено запросов = $this->queries_proceeded : \n";
        
$stat.="Собрано данных = $this->subdatas_received : \n";
        
$stat.="Текущая позиция = ".$queries->get_current_pos()." : \n";
        
$stat.="Всего надо обработать = ".$queries->get_count()." : \n";
        
$stat.="Число рабочих проксей : ".$proxies->get_count()."\n";
        
$time_work=0;
        if (
$this->end_time!=null)
            
$time_work=$this->end_time-$this->start_time;
        else
            
$time_work=time()-$this->start_time;
        
$stat.="Время работы = $time_work: \n";
        
$stat.="-------------------\n";

        
// запишем файл
        
CTextFile::write("out/stat.txt",$stat);
        return 
$stat;
    }

    
// проверить управляющие события
    
function check_controls_event()
    {
        
// обновить статистику сбора
        
if (file_exists("control/write_stat.control"))
        {            
            
// запишем статистику
            
$this->write_stat();

            
// удалим событие
            
unlink("control/write_stat.control");
            return 
"write_stat";
        }
        
// пауза
        
if (file_exists("control/pause.control"))
        {
            
// пауза
            
$pause=trim(CTextFile::get_line("control/pause.control",0),"\r\n");
            
sleep($pause);
            
            
// лог
            
global $log;
            
$log->event("Отработана пауза на $pause секунд");

            
// удалим событие
            
unlink("control/pause.control");
            return 
"pause";
        }
        
// добавить прокси
        
if (file_exists("control/add_proxy.control"))
        {    
            
// добавим прокси
            
global $proxies;
            
$proxies->add_proxy("control/add_proxy.control");    

            
// удалим событие
            
unlink("control/add_proxy.control");            
            return 
"add_proxy";
        }
        
// останов
        
if (file_exists("control/stop.control"))
        {
            
// удалим событие
            
unlink("control/stop.control");
            return 
"break";
        }
    }

    
// перезапуск
    
protected function restart()
    {
    }

    
// сохранить обработанные поисковые результаты в файл 
    
function run()
    {    
        
// время старта
        
$this->start_time=time();

        
// лог
        
global $log;

        
// число обработанных запросов в данный запуск
        
$this->queries_proceeded=1;
        
// число полученыых подданных
        
$this->subdatas_received=0;

        
// пройдемся по всем запросам        
        
while (true)
        {
            
// получим запрос
            
global $queries;
            
$query=$queries->get_next();
            if (
$query===null)
                break;        
    
            
// обработаем запрос, если это не запрещено
            
if (!$this->is_skip_query($query))
            {
                
// получим поисковые результаты для запроса через Google API (используя прокси)
                
if ($this->get($query))
                {
                    
// добавим поисковые результаты по заданному запросу в файл
                    
$this->subdatas_received+=$this->save();
                }
                else
                    break;
            }
            else
                
$log->event("skip $this->current_query");

            
// укажем что данные обработаны
            
$queries->step_complete();

            
// укажем общее количество обработанных данных
            
$this->queries_proceeded++;

            
// пауза между запросами
            
sleep($this->pause_per_request);

            
// проверить надобность перезапуска скрипта
            
if ($this->num_restart_after && $this->pages_proceeded>=$this->num_restart_after)
                
$this->restart();            
        }

        
// конец        
        
$log->event("Получено поисковых результатов по ".$this->queries_proceeded." запросам  ");    
        
// время окончания
        
$this->end_time=time();
    }

    
///////////////////////////////////////////////////
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
?>