Коротко: Создайте приложение на vk.com/dev, получите app_id и app_secret. Для авторизации - OAuth 2.0 через https://oauth.vk.com/authorize, получите access_token, используйте https://api.vk.com/method/METHOD_NAME для вызовов API. Версия API в 2015: 5.37.
Создание VK приложения
- vk.com/dev → «Создать приложение»
- Тип: «Веб-сайт»
- Адрес сайта:
https://mysite.ru - Базовый домен:
mysite.ru - Получаем:
app_idиapp_secret
Авторизация через VK Login
<?php
// VkAuth.php
class VkAuth {
private string $appId;
private string $appSecret;
private string $redirectUri;
public function __construct(string $appId, string $appSecret, string $redirectUri) {
$this->appId = $appId;
$this->appSecret = $appSecret;
$this->redirectUri = $redirectUri;
}
/**
* Сгенерировать URL для авторизации
* Permissions scope: https://vk.com/dev/permissions
*/
public function getAuthUrl(array $scope = ['email']): string {
$params = [
'client_id' => $this->appId,
'redirect_uri' => $this->redirectUri,
'scope' => implode(',', $scope),
'response_type' => 'code',
'v' => '5.37', // Версия API
'state' => bin2hex(random_bytes(16)), // CSRF-защита
];
$_SESSION['vk_state'] = $params['state'];
return 'https://oauth.vk.com/authorize?' . http_build_query($params);
}
/**
* Обменять code на access_token
* Вызывается на redirect_uri после авторизации
*/
public function handleCallback(string $code, string $state): array {
// Проверить CSRF state
if ($state !== ($_SESSION['vk_state'] ?? '')) {
throw new RuntimeException('Invalid state - possible CSRF');
}
$response = file_get_contents('https://oauth.vk.com/access_token?' . http_build_query([
'client_id' => $this->appId,
'client_secret' => $this->appSecret,
'redirect_uri' => $this->redirectUri,
'code' => $code,
]));
$data = json_decode($response, true);
if (isset($data['error'])) {
throw new RuntimeException('VK OAuth error: ' . $data['error_description']);
}
// $data содержит: access_token, user_id, email (если запрошен)
return $data;
}
}
VK API клиент
<?php
// VkApi.php
class VkApi {
private string $accessToken;
private string $apiVersion = '5.37';
private string $baseUrl = 'https://api.vk.com/method/';
public function __construct(string $accessToken) {
$this->accessToken = $accessToken;
}
public function call(string $method, array $params = []): array {
$params['access_token'] = $this->accessToken;
$params['v'] = $this->apiVersion;
$url = $this->baseUrl . $method;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_POST => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new RuntimeException("VK API HTTP error: $httpCode");
}
$data = json_decode($response, true);
if (isset($data['error'])) {
throw new RuntimeException(
'VK API error ' . $data['error']['error_code'] . ': ' . $data['error']['error_msg']
);
}
return $data['response'];
}
// Получить данные пользователя
public function getUser(int $userId): array {
$result = $this->call('users.get', [
'user_ids' => $userId,
'fields' => 'photo_100,city,bdate,sex',
]);
return $result[0];
}
// Опубликовать пост на стене сообщества
public function wallPost(int $ownerId, string $message, string $attachments = ''): int {
// ownerId для сообщества - отрицательный ID: -GROUP_ID
$result = $this->call('wall.post', [
'owner_id' => $ownerId,
'message' => $message,
'attachments' => $attachments, // 'photo-1234_5678,https://mysite.ru/article/1'
'from_group' => 1, // От имени сообщества (не пользователя)
]);
return $result['post_id'];
}
}
VK Login в контроллере
<?php
// routes: GET /auth/vk → login, GET /auth/vk/callback → callback
class AuthController {
public function vkLogin(): void {
$vkAuth = new VkAuth(VK_APP_ID, VK_APP_SECRET, 'https://mysite.ru/auth/vk/callback');
$authUrl = $vkAuth->getAuthUrl(['email']);
header('Location: ' . $authUrl);
exit;
}
public function vkCallback(): void {
$code = $_GET['code'] ?? '';
$state = $_GET['state'] ?? '';
try {
$vkAuth = new VkAuth(VK_APP_ID, VK_APP_SECRET, 'https://mysite.ru/auth/vk/callback');
$tokens = $vkAuth->handleCallback($code, $state);
$vkApi = new VkApi($tokens['access_token']);
$vkUser = $vkApi->getUser($tokens['user_id']);
// Найти или создать пользователя в БД
$user = UserRepository::findOrCreateByVk([
'vk_id' => $tokens['user_id'],
'email' => $tokens['email'] ?? null,
'first_name' => $vkUser['first_name'],
'last_name' => $vkUser['last_name'],
'avatar' => $vkUser['photo_100'],
]);
$_SESSION['user_id'] = $user['id'];
header('Location: /dashboard');
} catch (Exception $e) {
error_log('VK Auth error: ' . $e->getMessage());
header('Location: /login?error=vk_auth_failed');
}
exit;
}
}
Автопостинг новостей в группу VK
<?php
// Публикация новой статьи блога автоматически в VK-группу
// Запускается из cron после публикации
class VkPublisher {
private VkApi $api;
private int $groupId; // ID группы без минуса
public function publishArticle(array $article): void {
$message = $article['title'] . "\n\n"
. mb_substr(strip_tags($article['excerpt']), 0, 200) . "...\n\n"
. "Читать полностью: https://mysite.ru/blog/" . $article['slug'];
// Прикрепить ссылку как attachment
// VK автоматически загружает превью при публикации URL
$postId = $this->api->wallPost(
-$this->groupId,
$message,
'https://mysite.ru/blog/' . $article['slug']
);
error_log("Published to VK, post_id: $postId");
// Сохранить post_id для статистики
ArticleRepository::update($article['id'], ['vk_post_id' => $postId]);
}
}
Получение статистики группы
<?php
// Статистика сообщества за последние 7 дней
$stats = $vkApi->call('stats.get', [
'group_id' => GROUP_ID,
'date_from' => date('Y-m-d', strtotime('-7 days')),
'date_to' => date('Y-m-d'),
]);
foreach ($stats as $day) {
echo $day['day'] . ': ';
echo 'Охват: ' . ($day['reach'] ?? 0) . ', ';
echo 'Подписчики+: ' . ($day['subscribers']['joined'] ?? 0) . ', ';
echo 'Подписчики-: ' . ($day['subscribers']['left'] ?? 0) . "\n";
}
Rate Limits VK API 2015
ВКонтакте ограничивал: 3 запроса в секунду с одного access_token. При превышении - ошибка code: 6, Too many requests per second.
// Простой throttle через sleep
class ThrottledVkApi extends VkApi {
private float $lastRequest = 0;
public function call(string $method, array $params = []): array {
$elapsed = microtime(true) - $this->lastRequest;
if ($elapsed < 0.34) { // 3 req/sec = 333ms между запросами
usleep((int)((0.34 - $elapsed) * 1_000_000));
}
$this->lastRequest = microtime(true);
return parent::call($method, $params);
}
}
ВКонтакте оставался самой важной соцсетью для продвижения в России до 2018-2019, когда Instagram начал вытеснять его у молодёжной аудитории.