распознавание капчи в одну строку кода: мои классы для cUrl и сервиса antiCaptcha

Discussion in 'PHP' started by Дикс, 11 Jul 2009.

  1. Дикс

    Дикс Elder - Старейшина

    Joined:
    16 Apr 2006
    Messages:
    1,194
    Likes Received:
    227
    Reputations:
    26
    Продемонстрирую работу своей небольшой библиотечки. Выкалдываю исключительно для критики, код сыроват, но использование в любых целях возможно и допустимо.

    На самом деле библиотечка значительно больше, уже почти доросла до фреймворка, на котором я строил ботов для контакта и одноклассников, но другие классы ещё не готовы для опубликования - слишком многое хочется изменить и улучшить.

    Вот урезанная библиотека:
    PHP:
    <?php
    /**
    * aquascript - helpers for webscripts
    *          v 2.0 @ 18.06.2009-11.07.2009
    * by deex icq 86776690 Freedomscripts.org
    */
    class aquaCurl
    {
        private 
    $ptr 0;
        private 
    $lastResponse '';

        
    // все ключи описаны в конце этого скрипта
        
    private $options = array(
          
    CURLOPT_URL => '',
          
    CURLOPT_POST => 0// method POST
          
    CURLOPT_HEADER => 1// show headers
          
    CURLOPT_NOBODY => 0// disable body
          
    CURLOPT_FAILONERROR => 0,
          
    CURLOPT_TIMEOUT => 3600,
          
    CURLOPT_VERBOSE => 1,
          
    CURLOPT_FOLLOWLOCATION => 1,
          
    CURLOPT_POSTFIELDS => ''// post data. Content-Type:   ARRAY - multipart/form-data, STRING - application/x-www-form-urlencoded
          
    CURLOPT_RETURNTRANSFER => 1// return response
          
    CURLOPT_SSL_VERIFYPEER => 0// verify ssl sertificat
          
    CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
          
    CURLOPT_TIMEOUT => 30,
        
    //  CURLOPT_HTTPHEADER => array("Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7;","Keep-Alive: 300","Connection: keep-alive","Accept: */*")
          
    );

        private 
    $settingsRestore = array();
           public 
    $login '';
           public 
    $pass '';

        
    // reset options
        
    public function rst()
        {
            
    $this->options $this->settingsRestore;
        }

        function 
    __construct()
        {
            if (!
    extension_loaded('curl'))
                if (
    strtoupper(substr(PHP_OS03)) === 'WIN')
                    
    dl('curl.dll');
                else
                    
    dl('curl.so');

            if (!
    extension_loaded('curl'))
                die(
    "<b>Unable to load extension Curl! Application Exit</b><br/>");

            
    $this->settingsRestore $this->options;
        }

        public function 
    setAuth($login$pass)
        {
            
    $this->login $login;
            
    $this->pass $pass;
        }

        public function 
    set($key$val)
        {
            
    $this->options[$key] = $val;
        }

        public function 
    exec($return 1)
        {
            
    $this->ptr curl_init();

            if(!
    $this->ptr)
                die(
    'curl not initialized');

            if(
    $this->options[CURLOPT_POSTFIELDS] != '' || sizeof($this->options[CURLOPT_POSTFIELDS]) > 1)
                
    $this->options[CURLOPT_POST] = 1;

            
    curl_setopt($this->ptrCURLOPT_RETURNTRANSFER$this->options[CURLOPT_RETURNTRANSFER]);

            
    curl_setopt_array($this->ptr$this->options);

            
    $this->lastResponse curl_exec($this->ptr);

            if(
    $return)
                return 
    $this->lastResponse;
            else
                return 
    $this;
        }

        public function 
    debug()
        {
            
    $response '<strong>Info</strong><br /><br />';
            
    $info curl_getinfo($this->ptr);

            foreach(
    $info as $k => $v)
            {
                if(
    strstr($k'size'))
                    
    $v = ($v 1024) . ' kb';

                
    $response .= '<span style="color: #777">'.$k.':</span> '.$v.'<br />';
            }

            
    $response .= '<br />';

            if(
    $errNo curl_errno($this->ptr))
                
    $response .= '<strong>Error #'.$errNo.':</strong> '.curl_error($this->ptr).'<br />';

            return 
    $response;
        }

        public function 
    getResponseCode()
        {
            return 
    curl_getinfo($this->ptrCURLINFO_HTTP_CODE);
        }

        public function 
    getCookie()
        {
            
    $parse = array();
            
    preg_match_all("/Set-Cookie: ([0-9a-zA-Z\_\-=]*); /i"$this->lastResponse$parse);
            return (isset(
    $parse[1]) && sizeof($parse[1]))? implode('; '$parse[1]) : '';
        }

        public function 
    setCookie($cookie)
        {
            
    $this->options[CURLOPT_COOKIE] = trim($cookie);
            return 
    $this;
        }

        public function 
    clearCookie()
        {
            
    $this->options[CURLOPT_COOKIE] = '';
            return 
    $this;
        }

        function 
    __destruct()
        {
            if(
    $this->ptr)
                
    curl_close($this->ptr);

            if(isset(
    $_SESSION['curl_cookies']))
                unset(
    $_SESSION['curl_cookies']);
        }
    }

    //==============================================================================
    class antiCaptcha
    {
        private 
    $timeOut 5// timeout before read result
        
    private $acKey ''// ac-service.info key
        
    private $captchaID 0// when service get captcha - its return captcha id
        
    private $imageType 'jpg';
        private 
    $url = array(
                        
    'sendcaptcha' => 'http://ac-service.info/in.php',
                        
    'getinfo' => 'http://ac-service.info/res.php');

        private 
    $codes = array(
            
    'in' => array(
                
    'ERROR_KEY_DOES_NOT_EXIST' => 'incorrect anti-captcha key',
                
    'ERROR_NO_SLOT_AVAILABLE' => 'service busy, please try later',
                
    'ERROR_ZERO_CAPTCHA_FILESIZE' => 'captcha is empty file',
                
    'ERROR_TOO_BIG_CAPTCHA_FILESIZE' => 'captcha size bigger than 30 kb',
                
    'ERROR_WRONG_FILE_EXTENSION' => 'incorrect file extension (gif,jpg,png)'
                
    ),
            
    'res' => array(
                
    'ERROR_KEY_DOES_NOT_EXIST' => 'incorrect anti-captcha key',
                
    'ERROR_WRONG_ID_FORMAT' => 'uploaded captcha ID is not a number',
                
    'ERROR_NO_SUCH_CAPCHA_ID' => 'uploaded captcha ID is incorrect',
                
    'ERROR_URL_METHOD_FORBIDDEN' => 'method disabled',
                
    'CAPCHA_NOT_READY' => 'please wait..',
                
    'OK_REPORT_RECORDED' => 'complaint writed (only for reportbad function)',
            )
        );

        private 
    $captchaBody '';
        private 
    $curl '';
        public 
    $error '';

        public function 
    __construct($acKey$timeOut 5$imageType 'jpg'$curl)
        {
            
    $this->timeOut $timeOut;
            
    $this->acKey $acKey;
            
    $this->imageType $imageType;
            
    $this->curl = &$curl;
        }

        public function 
    get($url$cookie '')
        {
            
    $this->curl->rst();
            
    $this->curl->set(CURLOPT_URL$url);
            
    $this->curl->set(CURLOPT_BINARYTRANSFER1);
            
    $this->curl->set(CURLOPT_HEADER0);

            if(
    $cookie)
                
    $this->curl->setCookie($cookie);
            else
                
    $this->curl->clearCookie();

            
    $this->captchaBody $this->curl->exec();

            return (
    $this->captchaBody)? 0;
        }

        
    // get captcha body
        
    public function send()
        {
            
    $postData = array(
                
    'method'    => 'base64',
                
    'key'       => $this->acKey,
                
    'body'      => base64_encode($this->captchaBody),
                
    'ext'     => $this->imageType
            
    );

            
    $this->curl->rst();
            
    $this->curl->set(CURLOPT_URL$this->url['sendcaptcha']);
            
    $this->curl->set(CURLOPT_POSTFIELDS$postData);
            
    $this->curl->set(CURLOPT_HEADER1);
            
    $this->curl->set(CURLOPT_NOBODY0);
            
    $this->curl->set(CURLOPT_RETURNTRANSFER1);
            
    $return $this->curl->clearCookie()->exec();

            if(
    strstr($return'OK|'))
            {
                
    preg_match('/OK\|(.*)/'$return$resp);
                
    $this->captchaID $resp[1];

                return 
    1;
            }else{
                
    $this->error = (isset($this->codes['in'][$return]))? $this->codes['in'][$return] : 'cant send';
                return 
    0;
            }
        }

        public function 
    save($name)
        {
            if(
    $this->captchaBody)
            {
                
    file_put_contents($name$this->captchaBody);
                return 
    1;
            }else
                return 
    0;
        }

        public function 
    load($captcha)
        {
            
    $this->captchaBody file_get_contents($captcha);
            return !!
    $this->captchaBody;
        }

        public function 
    recognize()
        {
            
    $tries 5;

            while(
    $tries--)
            {
                
    $postData = array(
                    
    'key' => $this->acKey,
                    
    'action' => 'get',
                    
    'id' => $this->captchaID
                
    );

                
    $this->curl->rst();
                
    $this->curl->set(CURLOPT_URL$this->url['getinfo']);
                
    $this->curl->set(CURLOPT_POSTFIELDS$postData);
                
    $this->curl->set(CURLOPT_HEADER1);
                
    $this->curl->set(CURLOPT_RETURNTRANSFER1);
                
    $this->curl->set(CURLOPT_NOBODY0);
                
    $this->curl->set(CURLOPT_FOLLOWLOCATION1);
                
    $return $this->curl->clearCookie()->exec();

                if(
    strstr($return'OK|'))
                {
                    
    preg_match('/OK\|(.*)/'$return$resp);
                    return 
    $resp[1];

                }else{
                    
    sleep($this->timeOut);
                }
            }
        }

        public function 
    simple($first$second '')
        {
            
    $res = (stristr($first'http://'))? $this->get($first$second) : $this->load($first);

            if(
    $res && $this->send())
                return 
    $this->recognize();
        }
    }
    В данном случае работу с aquacurl я описывать не буду, там всё интуитивно понятно :cool:

    Приведу примеры распознавания капчи с помощью ac-service.info (AntiCaptcha)

    PHP:
    //убираем лимит, включаем ошибки, инклудим библиотеку
    set_time_limit(0);
    error_reporting(7);

    include(
    'ascript.php');

    // url до капчи, куки (опционально), ключ антикапчи (брать на сайте сервиса)
    $url 'http://vkontakte.ru/captcha.php?s=1&sid=248439795815';
    $cookie 'куки';
    $acKey 'abd6*******426';

    // инициализируем класс работы с курл
    $curl = new aquacurl;
    // инициализируем класс работы с антикапчей
    // передаём ей ключ, задержку в секундах при проверке результата распознания 
    // капчи на сервисе, формат капчи, ссылку на созданный класс работы с curl
    $ac = new anticaptcha($acKey5'jpg', &$curl);

    // ================ МЕТОД 1 ПРОСТОЙ

    // передали урл и куки (опционально) - получили код капчи
    $key $ac->simple($url$cookie);
    // либо передали имя файла (ну и путь если надо)
    $key $ac->simple('captcha.jpg');



    // ================  МЕТОД 2 РАСШИРЕННЫЙ
    // грузим капчу с урла (+ куки)
    $ac->get($url$cookie);

    // если удалось отправить
    if($ac->send())
    {
                
    // распознаем
        
    $key $ac->recognize();
               
    // заодно смотрим ошибки
        
    $error $ac->error;
    }

    // если капча уже есть в файле, то грузим из файла
    $ac->load('captcha.jpg'); // а потом отправляем и распознаем

    // если надо сохрнить капчу - указываем имя файла
    $ac->save('captcha.jpg');
    Вот и всё :)
    Надеюсь код окажется кому-либо полезным, в любом случае я жду конструктивной критики и замечаний.
     
    2 people like this.
  2. Дикс

    Дикс Elder - Старейшина

    Joined:
    16 Apr 2006
    Messages:
    1,194
    Likes Received:
    227
    Reputations:
    26
    может и есть, но меня интересуют именно тонкости реализации :)