Для получения полного доступа
зарегистрируйтесь

Работа с API VK в Yii2


Yii2 VK

Компонент для расширенной работы с ВК API в YII2. Загрузка изображений, распознавание капчи, постановка очередей и многое другое.

Сайт с подробным описанием yii2 api vk GitHub

Особенности

  • Задержка выполнения
  • Разделины post и get
  • Загрузка изображений
  • Добавление в очереди
  • Запись задач и выполнению их по cron-у
  • Интеграция с распознованием капчи
  • Запись в атрибуты token-а

Установка

Предпочтительный способ установить это расширение через composer.

Либо запустить

php composer.phar require --prefer-dist jumper423/yii2-vk "*"

или добавить

"jumper423/yii2-vk": "*"

в файл composer.json.

Конфигурация

'components' => [
    'vk' => [
        'class' => 'jumper423\VK',
        'clientId' => '11111',
        'clientSecret' => 'n9wsv98svSD867SA7dsda87',
        'delay' => 0.7, // Минимальная задержка между запросами
        'delayExecute' => 120, // Задержка между группами инструкций в очереди
        'limitExecute' => 1, // Количество инструкций на одно выполнении в очереди
        'captcha' => 'captcha', // Компонент по распознованию капчи
    ],
],
'aliases' => [
    '@actions' => '@backend/runtime/cron', // Папка куда будут складироваться очереди для cron-а
],

"Расшиненая" конфигурация

'components' => [
    'captcha' => [
        'class' => 'jumper423\Captcha',
        'pathTmp' => '@imagescache/captcha',
        'apiKey' => '42eab4119020dbc729f657',
    ],
    'authClientCollection' => [
        'class' => 'yii\authclient\Collection',
        'clients' => [
            'vkontakte' => [
                'class' => 'jumper423\VK',
                'clientId' => '11111',
                'clientSecret' => 'n9wsv98svSD867SA7dsda87',
                'delay' => 0.7,
                'delayExecute' => 120,
                'limitExecute' => 1,
                'captcha' => 'captcha',
                'scope' => 'friends,photos,pages,wall,groups,email,stats,ads,offline,notifications', //,messages,nohttps
                'title' => 'ВКонтакте'
            ],
        ],
    ],
],
'aliases' => [
    '@actions' => '@backend/runtime/cron', // Папка куда будут складироваться очереди для cron-а
],

Использование

Вызов следовательно

/**
* @var jumper423\VK $vk
*/

$vk = Yii::$app->vk;

или

$vk = Yii::$app->authClientCollection->getClient('vkontakte');

Создание альбома

$response = $vk->post('photos.createAlbum', ['group_id' => $groupId, 'title' => $title, 'upload_by_admins_only' => 1]);

Добавление инструкции в очередь

foreach ($images as $image) {
    $vk->addAction('photos.edit', ['caption' => $caption, 'owner_id' => $ownerId, 'photo_id' => $image,]);
}
// Добавление в cron
$vk->addActionsInCron('photos.edit');
// Или начать выполнение очереди командой
// $vk->performAnAction();

Выполнение cron-а

$vk->performAnActionFromCron('photos.edit');

Загрузка изображения в альбом пользователя или группы

$imageId = $vk->loadImage($imagePath, $albumId, $groupId);
<?php

namespace jumper423;

use Yii;
use yii\authclient\clients\VKontakte;
use yii\base\Exception;
use yii\helpers\ArrayHelper;
use yii\helpers\Json;

class VK extends VKontakte
{
    public $delay = 0.7;
    public $delayExecute = 120;
    public $limitExecute = 1;
    /**
     * @var null|string|Captcha
     */
    public $captcha = 'captcha';
    private $lastRequest = null;
    private $sleepRandMin = 0;
    private $sleepRandMax = 500;
    private $execute = [];
    const MILLISECOND = 1000;
    
    /**
     * @inheritdoc
     */
    public function __construct($config = [])
    {
        parent::__construct($config);
        if (is_string($this->captcha)) {
            if (Yii::$app->has($this->captcha) && Yii::$app->get($this->captcha) instanceof CaptchaInterface) {
                $this->captcha = Yii::$app->get($this->captcha);
            } else {
                $this->captcha = null;
            }
        } elseif (is_object($this->captcha)) {
            if (!($this->captcha instanceof CaptchaInterface)) {
                $this->captcha = null;
            }
        } else {
            $this->captcha = null;
        }
    }
    
    /**
     * @param bool|false $delay
     */
    private function sleep($delay = false)
    {
        if ($delay === false) {
            $delay = $this->delay;
        }
        if ($this->lastRequest === null) {
            $this->lastRequest = microtime(true);
        } else {
            $microtime = microtime(true);
            if ($this->lastRequest + $delay > $microtime) {
                sleep($this->lastRequest + $delay - $microtime);
                $this->lastRequest = microtime(true);
            }
        }
        sleep(rand($this->sleepRandMin, $this->sleepRandMax) / self::MILLISECOND);
    }
    
    /**
     * @inheritdoc
     */
    public function api($apiSubUrl, $method = 'GET', array $params = [], array $headers = [], $delay = false)
    {
        $this->sleep($delay);
        $response = parent::api($apiSubUrl, $method, $params, $headers);
        if (ArrayHelper::getValue($response, 'error.error_code') == 14 && $this->captcha) {
            if ($this->captcha->run(ArrayHelper::getValue($response, 'error.captcha_img'))) {
                $response = $this->api($apiSubUrl, $method, ArrayHelper::merge($params,
                    [
                        'captcha_sid' => ArrayHelper::getValue($response, 'error.captcha_sid'),
                        'captcha_key' => $this->captcha->result()
                    ])
                    , $headers);
            } else {
                throw new Exception($this->captcha->error());
            }
        } elseif (ArrayHelper::getValue($response, 'error')) {
            throw new Exception(ArrayHelper::getValue($response, 'error.error_msg'), ArrayHelper::getValue($response, 'error.error_code'));
        }
        return $response;
    }
    
    /**
     * @param $apiSubUrl
     * @param array $params
     * @param array $headers
     * @param bool|false $delay
     * @return array
     * @throws Exception
     */
    public function post($apiSubUrl, array $params = [], array $headers = [], $delay = false)
    {
        return $this->api($apiSubUrl, 'POST', $params, $headers, $delay);
    }
    
    /**
     * @param $apiSubUrl
     * @param array $params
     * @param array $headers
     * @param bool|false $delay
     * @return array
     * @throws Exception
     */
    public function get($apiSubUrl, array $params = [], array $headers = [], $delay = false)
    {
        return $this->api($apiSubUrl, 'GET', $params, $headers, $delay);
    }
    
    /**
     * @param $apiSubUrl
     * @param array $params
     */
    public function addAction($apiSubUrl, array $params = [])
    {
        $this->execute[] = "API.{$apiSubUrl}(" . Json::encode($params) . ")";
    }
    
    /**
     * @param $method
     */
    public function addActionsInCron($method)
    {
        $json = Json::decode(file_get_contents(Yii::getAlias("@actions/{$method}.json")));
        $json = ArrayHelper::merge($json, $this->execute);
        file_put_contents(Yii::getAlias("@actions/{$method}.json"), Json::encode($json));
    }
    
    /**
     * @param $method
     * @return array
     */
    public function performAnActionFromCron($method)
    {
        $response = [];
        do {
            $execute = Json::decode(file_get_contents(Yii::getAlias("@actions/{$method}.json")));
            if (count($execute)) {
                $executeRow = array_shift($execute);
                $response = ArrayHelper::merge($response, $this->post('execute', ['code' => "return \n [" . $executeRow . "];"]));
                $execute = Json::decode(file_get_contents(Yii::getAlias("@actions/{$method}.json")));
                $r = array_search($executeRow, $execute);
                if ($r !== false) {
                    unset($execute[$r]);
                    file_put_contents(Yii::getAlias("@actions/{$method}.json"), Json::encode($execute));
                }
                sleep($this->delayExecute);
            } else {
                break;
            }
        } while (true);
        return $response;
    }
    
    /**
     * @return array
     */
    public function performAnAction()
    {
        $executeCount = count($this->execute);
        $response = [];
        for ($i = 0; $executeCount > $i; $i += $this->limitExecute) {
            $response = ArrayHelper::merge($response, $this->post('execute', ['code' => "return \n [" . implode(",\n", array_slice($this->execute, $i, $this->limitExecute)) . "];"]));
            sleep($this->delayExecute);
        }
        $this->execute = [];
        return $response;
    }
    
    /**
     * @param $imagePath
     * @param $albumId
     * @param null|int $groupId
     * @return int
     * @throws Exception
     */
    public function loadImage($imagePath, $albumId, $groupId = null)
    {
        $params = ['album_id' => $albumId];
        if ($groupId) {
            $params['group_id'] = $groupId;
        }
        $request = $this->post('photos.getUploadServer', $params);
        $uploadUrl = ArrayHelper::getValue($request, 'response.upload_url');
        if ($uploadUrl) {
            $ch = curl_init($uploadUrl);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, [
                'file1' => "@" . $imagePath
            ]);
            $paramsSave = Json::decode(curl_exec($ch));
            curl_close($ch);
            if (count($paramsSave)) {
                return ArrayHelper::getValue($this->post('photos.save', $paramsSave), 'response.0.pid');
            } else {
                throw new Exception('Empty params save');
            }
        } else {
            throw new Exception('Not upload_url');
        }
    }
    
    /**
     * @inheritdoc
     */
    protected function initUserAttributes()
    {
        $response = $this->api('users.get.json', 'GET', [
            'fields' => implode(',', $this->attributeNames),
        ]);
        $attributes = array_shift($response['response']);
        $accessToken = $this->getAccessToken();
        if (is_object($accessToken)) {
            $accessTokenParams = $accessToken->getParams();
            $attributes = array_merge($accessTokenParams, $attributes);
        }
        return $attributes;
    }
}

Чтобы увидеть комментарии, нужно быть участником сообщества

Регистрация