За последние 24 часа нас посетили 18153 программиста и 1684 робота. Сейчас ищут 1115 программистов ...

Работа с API Вконтакте через PHP

Тема в разделе "Решения, алгоритмы", создана пользователем Ensiferum, 28 фев 2011.

  1. Ensiferum

    Ensiferum Активный пользователь

    С нами с:
    11 июл 2010
    Сообщения:
    1.292
    Симпатии:
    0
    Адрес:
    из секты поклонников Нео
    Многие знают о том, что у контакта есть API для различных действий. С помощью них можно и сообщение от имени пользователя послать, и его френдленту получить. Но проблема (по крайней мере для меня это проблема) в том, что не все методы API можно вызвать через сайт, для некоторых нужны desktop-решения. Вконтакте это описано так: внутри программы ставим компонент браузера, в который будет выводится форма с разрешением некоторых прав для программы и пользователь сам выбирает, что разрешить. Далее форма переходит на специальный адрес и из ссылки после # вытаскиваются необходимые параметры.

    Решил обойти это ограничение. Накатал небольшой класс

    PHP:
    1. <?php
    2.  
    3. class vkapi {
    4.     public $mid             = '';
    5.     public $sid             = '';
    6.     public $secret          = '';
    7.     public $expire          = '';
    8.     public $settings        = '';
    9.     public $settings_hash   = '';
    10.     public $user_first_name = '';
    11.     public $user_full_name  = '';
    12.     public $user_thumb      = '';
    13.     public $auth_hash       = '';
    14.     public $sig             = '';
    15.     private $api_id         = '';
    16.     public $cookie          = '';       // печеньки
    17.     public $remixsid        = '';       // главная печенька
    18.     public $antigateHash    = '';
    19.    
    20.     public function __construct($api_id='') {
    21.         $this->api_id = $api_id;
    22.     }
    23.    
    24.     public function get($url, $follow=1) {
    25.         $process = curl_init($url);
    26.         curl_setopt($process, CURLOPT_HEADER, 1);
    27.         curl_setopt($process, CURLOPT_USERAGENT, 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; ru-ru) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7');
    28.         curl_setopt($process, CURLOPT_COOKIE,$this->cookie);
    29.         curl_setopt($process, CURLOPT_TIMEOUT, 15);
    30.         curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
    31.         curl_setopt($process, CURLOPT_FOLLOWLOCATION, $follow);
    32.  
    33.         $return = curl_exec($process);
    34.         curl_close($process);
    35.         return $return;
    36.     }
    37.  
    38.     public function post($url, $data, $follow=1) {
    39.         $process = curl_init($url);
    40.         curl_setopt($process, CURLOPT_HEADER, 1);
    41.         curl_setopt($process, CURLOPT_USERAGENT, 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; ru-ru) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7');
    42.         curl_setopt($process, CURLOPT_COOKIE,$this->cookie);
    43.         curl_setopt($process, CURLOPT_TIMEOUT, 15);
    44.         curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
    45.         curl_setopt($process, CURLOPT_FOLLOWLOCATION, $follow);
    46.         curl_setopt($process, CURLOPT_POST, 1);
    47.         curl_setopt($process, CURLOPT_POSTFIELDS, $data);      
    48.  
    49.         $return = curl_exec($process);
    50.         curl_close($process);
    51.         return $return;
    52.     }  
    53.     public function doAppPermit() {
    54.         /* Возвращается объект со следующими значениями:
    55.         expire  Время истечения сессии в формате UNIX
    56.         mid     ID пользователя в ВКонтакте
    57.         secret  Специально сгенерированный секрет сессии
    58.         sid     Идентификатор сессии
    59.         */
    60.         $resp = $this->getBody($this->post('http://vkontakte.ru/login.php', 'act=a_auth&app='.$this->api_id.'&hash='.$this->auth_hash.'&permanent=1'));
    61.         if ($obj = @json_decode($resp)) {
    62.             $this->mid      = $obj->mid;
    63.             $this->sid      = $obj->sid;
    64.             $this->secret   = $obj->secret;
    65.             $this->expire   = $obj->expire;
    66.         } else return false;
    67.     }
    68.    
    69.     public function doLogin($login, $pass) {
    70.         // 1 шаг
    71.         $resp = $this->post('http://vkontakte.ru/login.php?app='.$this->api_id.'&layout=popup&type=browser&settings=16383', '',1);
    72.         $this->getCookie($resp);
    73.         $match = array();
    74.         preg_match('#type=("|\')hidden("|\')\sname=("|\')app_hash("|\')\svalue=("|\')(.*)("|\')#Us', $resp, $match[]);
    75.         preg_match('#type=("|\')hidden("|\')\sname=("|\')vk("|\')\svalue=("|\')(.*)("|\')#Us', $resp, $match[]);
    76.         preg_match('#type=("|\')hidden("|\')\sname=("|\')permanent("|\')\svalue=("|\')(.*)("|\')#Us', $resp, $match[]);
    77.         preg_match('#type=("|\')hidden("|\')\sname=("|\')al_test("|\')\svalue=("|\')(.*)("|\')#Us', $resp, $match[]);
    78.  
    79.         $postdata = "act=login&app={$this->api_id}&app_hash={$match[0][6]}&vk={$match[1][6]}&captcha_sid=&al_test={$match[3][6]}&captcha_key=&email={$login}&pass={$pass}&expire=&permanent={$match[2][6]}";
    80.  
    81.         // 2 Шаг
    82.         $resp = $this->post('http://login.vk.com/', $postdata, 0);
    83.         $this->cookie = '';
    84.         $this->getCookie($resp);
    85.  
    86.         if (preg_match_all('#name=("|\')(.*)("|\')\svalue=("|\')(.*)("|\')#Us', $resp, $match)) {
    87.             $postdata = '';
    88.        
    89.             foreach ($match[2] as $k => $v) {
    90.                 $postdata .= $match[2][$k] . '=' . $match[5][$k] . '&';
    91.             }
    92.             $postdata = substr($postdata, 0, -1);
    93.            
    94.             preg_match('#name=("|\')s("|\')\svalue=("|\')(.*)("|\')#Us', $resp, $match);
    95.             $this->remixsid = $match[4];
    96.            
    97.             // 3 Шаг
    98.             $resp = $this->post('http://vkontakte.ru/login.php', $postdata, 0);
    99.  
    100.             if (preg_match('#<script type="text/javascript">parent.onDone\((.*)\)<\/script>#Us', $resp, $match)) {
    101.                 $obj = json_decode(iconv("WINDOWS-1251", "UTF-8", $match[1]));
    102.                 $this->mid              = $obj->mid;
    103.                 $this->sid              = $obj->sid;
    104.                 $this->secret           = $obj->secret;
    105.                 $this->expire           = $obj->expire;
    106.                 $this->settings         = $obj->settings;
    107.                 $this->settings_hash    = $obj->settings_hash;
    108.                 $this->user_first_name  = $obj->user_first_name;
    109.                 $this->user_full_name   = $obj->user_full_name;
    110.                 $this->user_thumb       = $obj->user_thumb;
    111.                 $this->auth_hash        = $obj->auth_hash;
    112.  
    113.                 return true;
    114.             } else return false;
    115.         } else return false;
    116.     }
    117.    
    118.     public function desktop_api($method, $data='') {
    119.         $sig = '';
    120.        
    121.         $postdata = array(
    122.             'api_id'    => $this->api_id,
    123.             'v'         => '3.0',
    124.             'format'    => 'JSON',
    125.             'method'    => $method
    126.         );
    127.        
    128.         if ($data) {
    129.             foreach ($data as $k => $v) {
    130.                     $postdata[$k] = $v;
    131.             }
    132.         }
    133.         ksort($postdata, SORT_STRING);
    134.  
    135.         foreach ($postdata as $k => $v)
    136.             $sig .= $k . '=' . $v;
    137.        
    138.         $sig = md5($this->mid . $sig . $this->secret);     
    139.  
    140.         $postdata['sig'] = $sig;
    141.         $postdata['sid'] = $this->sid;
    142.  
    143.         $resp = $this->post('http://api.vkontakte.ru/api.php', $postdata);
    144.         return $resp;
    145.     }
    146.  
    147.     public function saveSettings() {
    148.         $this->cookie = "remixchk=5; remixsid=".$this->remixsid;
    149.  
    150.         $postdata = array('addMember' => 1, 'id' => $this->api_id, 'hash' => $this->settings_hash, 'app_settings_8192' => 1, 'app_settings_4096' => 1,'app_settings_2048' => 1,'app_settings_1024' => 1,'app_settings_512' => 1,'app_settings_256' => 1,'app_settings_128' => 1,'app_settings_64' => 1,'app_settings_32' => 1,'app_settings_16' => 1,'app_settings_8' => 1);
    151.         $resp = $this->post('http://vkontakte.ru/apps.php?act=a_save_settings', $postdata, 1); 
    152.        
    153.         // Работаем с капчей
    154.         if (preg_match('#"captcha_sid":"(.*)"#Us', $resp, $match)) {
    155.             if ($this->antigateHash) {
    156.                 $temp = $this->getBody($this->get('http://m.vkontakte.ru/captcha?s=1&sid='.$match[1]));
    157.  
    158.                 file_put_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'captcha'. DIRECTORY_SEPARATOR . $match[1].'.jpg',$temp);
    159.                 $temp = $this->captcha(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'captcha'. DIRECTORY_SEPARATOR . $match[1].'.jpg');
    160.                
    161.                 $postdata['captcha_sid'] = $match[1];
    162.                 $postdata['captcha_key'] = $temp;
    163.                
    164.                 $resp = $this->post('http://vkontakte.ru/apps.php?act=a_save_settings', $postdata, 1);
    165.             } else {
    166.                 return false;
    167.             }  
    168.         } else {
    169.             return true;
    170.         }
    171.     }
    172.    
    173.     // Достаем из запроса кукисы
    174.     private function getCookie($data) {
    175.         if (preg_match_all('#Set-Cookie: (.*);#Us',$data,$match))
    176.             $this->cookie .= implode('; ',$match[1]);
    177.     }  
    178.    
    179.     // Возвращает текст ответа сервера без заголовка
    180.     public function getBody($text) {
    181.         return array_pop(explode(PHP_EOL.PHP_EOL,$text));
    182.     }
    183.  
    184.     public function captcha($captchaFile) {
    185.         $rtimeout = 5;
    186.         $mtimeout = 90;
    187.         $postdata = array(
    188.             'method'    => 'post',
    189.             'key'       => $this->antigateHash,
    190.             'file'      => '@'.$captchaFile,
    191.             'phrase'    => 0,
    192.             'regsense'  => 1,
    193.             'numeric'   => 0,
    194.             'min_len'   => 4,
    195.             'max_len'   => 7
    196.         );
    197.  
    198.         $result =  $this->post('http://www.antigate.com/in.php', $postdata);
    199.  
    200.         if (strpos($result, "ERROR")!==false) {
    201.             $this->captchaDebug = $this->getBody($result);
    202.             return false;
    203.         }
    204.         else {
    205.             $ex = explode("|", $result);
    206.             $captcha_id = $ex[1];
    207.             $waittime = 0;
    208.             sleep($rtimeout);
    209.             $time1 = microtime(true);
    210.             while(true) {
    211.                 $result = @file_get_contents('http://antigate.com/res.php?key='.$this->antigateHash.'&action=get&id='.$captcha_id);
    212.                 if (strpos($result, 'ERROR')!==false) {
    213.                     $this->captchaDebug = $result;
    214.                     return false;
    215.                 }
    216.                 if ($result=="CAPCHA_NOT_READY") {
    217.                     $waittime += $rtimeout;
    218.                     if ($waittime>$mtimeout) {
    219.                         $this->captchaDebug = 'Time expired';
    220.                         break;
    221.                     }
    222.                     sleep($rtimeout);
    223.                 }
    224.                 else {
    225.                     $ex = explode('|', $result);
    226.                     if (trim($ex[0])=='OK') {
    227.                         $this->captchaTime = microtime(true) - $time1;
    228.                         return trim($ex[1]);
    229.                     }
    230.                 }
    231.             }
    232.             return false;
    233.         }
    234.     }  
    235. }
    236. ?>
    Его применение:

    PHP:
    1. <?php
    2. $api_id = '456654';
    3. $login  = [email='asd@asd.ru]'asd@asd.ru[/email]';
    4. $pass   = 'qwe';
    5.  
    6. $vk = new vkapi($api_id);
    7.  
    8. if ($vk->doLogin($login, $pass)) {
    9.     $vk->saveSettings();
    10.     $vk->doAppPermit();
    11.            
    12.     $text = $vk->getBody($vk->desktop_api('newsfeed.get', ''));
    13.     echo $text;
    14. }
    15. ?>
    Фишка в том, что скрытно можно добавить пользователю любое приложение с полными правами. Пытался узнать в группе по API о том, не нарушаю ли я таким образом каких-либо прав - никто не ответил. Так что, если кому интересно, пользуйтесь.

    Также всегда интересны ремарки по коду!
     
  2. goshalve

    goshalve Guest

    Много букв.
    Чего программа делает по русски?
     
  3. Ensiferum

    Ensiferum Активный пользователь

    С нами с:
    11 июл 2010
    Сообщения:
    1.292
    Симпатии:
    0
    Адрес:
    из секты поклонников Нео
    обходит стандартный метод реализации, пригоден для использования в PHP
     
  4. andreyukricq

    andreyukricq Активный пользователь

    С нами с:
    30 мар 2011
    Сообщения:
    2
    Симпатии:
    0
    Адрес:
    Украина
    А можно сделать так чтобы пользователь вводил свои пароль и логин на сайте контакта как при OPEN API авторизации, если есть такие наработки поделитесь.
    У меня начало кагбЭ :D есть т.е. открывается окошко в котором вводим пароль и логин, перебрасывает на страницу

    где
    http://vkontakte.ru/api/login_success.html#session={%22mid%22%3A3242346576%2C%22sid%22%3A%22d1b2942597672176bee39dcee1a5030fb4a2d5008d7fd2b903cdf7e6d415ae%22%2C%22secret%22%3A%22eefd544eb3%22%2C%22expire%22%3A0%2C%22sig%22%3A%22e2e931fg3rt545f6233e38bb3188f11e0%22}

    а вот данные сессии не знаю как вернуть обратно в php (по ходу надо javascript использовать, но я блин в нем не силен)
    подскажите как быть...
     
  5. Ensiferum

    Ensiferum Активный пользователь

    С нами с:
    11 июл 2010
    Сообщения:
    1.292
    Симпатии:
    0
    Адрес:
    из секты поклонников Нео
    совершенно другой подход
     
  6. andreyukricq

    andreyukricq Активный пользователь

    С нами с:
    30 мар 2011
    Сообщения:
    2
    Симпатии:
    0
    Адрес:
    Украина
    Ответ

    Как можно с их домена с помощью javascript в браузере перетянуть данные?