6 Commits
2.0.7 ... 2.1.2

Author SHA1 Message Date
42969feac6 Update VkUser.php 2025-01-11 02:05:15 +03:00
b7fce352c9 uod 2025-01-11 01:53:35 +03:00
99d4587b3b UPD to php 8.4 2025-01-11 01:36:15 +03:00
7f917ed0cb upd 2024-06-14 11:59:56 +03:00
c931c55478 Update VkProvider.php 2024-06-13 21:50:27 +03:00
00c4ccc601 upd 2024-06-13 21:44:05 +03:00
6 changed files with 285 additions and 170 deletions

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@ build
composer.lock composer.lock
docs docs
vendor vendor
.php-cs-fixer.cache
.phpcs-cache

View File

@@ -1,5 +1,6 @@
{ {
"name": "1sept/oauth2-vkontakte", "name": "1sept/oauth2-vkontakte",
"version": "2.1.2",
"description": "VK provider for league/oauth2-client", "description": "VK provider for league/oauth2-client",
"keywords": [ "keywords": [
"league", "league",
@@ -13,7 +14,7 @@
} }
], ],
"require": { "require": {
"php" : ">=8.1", "php" : ">=8.3",
"league/oauth2-client": "^2.0" "league/oauth2-client": "^2.0"
}, },
"require-dev": { "require-dev": {

20
phpcs.xml.dist Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<arg name="basepath" value="."/>
<arg name="cache" value=".phpcs-cache"/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<rule ref="PSR12">
<exclude name="Generic.Files.LineLength"/>
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"/>
</rule>
<file>src/</file>
</ruleset>
<!-- composer require "squizlabs/php_codesniffer=*" dev -->

14
phpstan.dist.neon Normal file
View File

@@ -0,0 +1,14 @@
parameters:
level: 5
paths:
- bin/
- config/
- public/
- src/
errorFormat: table
editorUrl: 'vscode://file/%%file%%:%%line%%'
editorUrlTitle: '%%relFile%%:%%line%%'
ignoreErrors:
- '#Construct empty\(\) is not allowed. Use more strict comparison.#'

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Sept\OAuth2\Client\Provider; namespace Sept\OAuth2\Client\Provider;
use League\OAuth2\Client\Provider\AbstractProvider; use League\OAuth2\Client\Provider\AbstractProvider;
@@ -9,10 +11,10 @@ use Psr\Http\Message\ResponseInterface;
class VkProvider extends AbstractProvider class VkProvider extends AbstractProvider
{ {
protected $baseOAuthUri = 'https://oauth.vk.com'; protected string $baseOAuthUri = 'https://oauth.vk.com';
protected $baseUri = 'https://api.vk.com/method'; protected string $baseUri = 'https://api.vk.com/method';
protected $version = '5.236'; protected float $version = 5.199;
protected $language = null; protected ?string $language = null;
/** /**
* @see https://vk.com/dev/permissions * @see https://vk.com/dev/permissions
@@ -38,8 +40,8 @@ class VkProvider extends AbstractProvider
// 'status', // 'status',
// 'video', // 'video',
]; ];
/** /**
* @type array
* @see https://new.vk.com/dev/fields * @see https://new.vk.com/dev/fields
*/ */
public array $userFields = [ public array $userFields = [
@@ -60,6 +62,8 @@ class VkProvider extends AbstractProvider
'photo_max_orig', 'photo_max_orig',
'screen_name', 'screen_name',
'sex', 'sex',
'deactivated',
'is_closed',
// 'about', // 'about',
// 'activities', // 'activities',
// 'blacklisted', // 'blacklisted',
@@ -111,12 +115,9 @@ class VkProvider extends AbstractProvider
// 'wall_comments', // 'wall_comments',
]; ];
/**
* @param string $language
*/
public function setLanguage(string $language): self public function setLanguage(string $language): self
{ {
$this->language = (string)$language; $this->language = $language;
return $this; return $this;
} }
@@ -137,17 +138,19 @@ class VkProvider extends AbstractProvider
'fields' => $this->userFields, 'fields' => $this->userFields,
'access_token' => $token->getToken(), 'access_token' => $token->getToken(),
'v' => $this->version, 'v' => $this->version,
'lang' => $this->language 'lang' => $this->language,
]; ];
$query = $this->buildQueryString($params); $query = $this->buildQueryString($params);
$url = "$this->baseUri/users.get?$query"; $url = "$this->baseUri/users.get?$query";
return $url; return $url;
} }
protected function getDefaultScopes()
protected function getDefaultScopes(): array
{ {
return $this->scopes; return $this->scopes;
} }
protected function checkResponse(ResponseInterface $response, $data): void protected function checkResponse(ResponseInterface $response, $data): void
{ {
// Metadata info // Metadata info
@@ -157,12 +160,13 @@ class VkProvider extends AbstractProvider
// Response info // Response info
$responseCode = $response->getStatusCode(); $responseCode = $response->getStatusCode();
$responseMessage = $response->getReasonPhrase(); $responseMessage = $response->getReasonPhrase();
// Data info // Data info
$error = !empty($data['error']) ? $data['error'] : null; $error = !empty($data['error']) ? $data['error'] : null;
$errorCode = !empty($error['error_code']) ? $error['error_code'] : $responseCode; $errorCode = !empty($error['error_code']) ? $error['error_code'] : $responseCode;
$errorDescription = !empty($data['error_description']) ? $data['error_description'] : null; $errorDescription = !empty($data['error_description']) ? $data['error_description'] : null;
$errorMessage = !empty($error['error_msg']) ? $error['error_msg'] : $errorDescription; $errorMessage = !empty($error['error_msg']) ? $error['error_msg'] : $errorDescription;
$message = $errorMessage ?: $responseMessage; $message = (bool) $errorMessage ? $errorMessage : $responseMessage;
// Request/meta validation // Request/meta validation
if (399 < $responseCode) { if (399 < $responseCode) {
@@ -170,89 +174,93 @@ class VkProvider extends AbstractProvider
} }
// Content validation // Content validation
if ('application/json' != $contentType) { if ('application/json' !== $contentType) {
throw new IdentityProviderException($message, $responseCode, $data); throw new IdentityProviderException($message, $responseCode, $data);
} }
if ($error) { if ($error) {
throw new IdentityProviderException($errorMessage, $errorCode, $data); throw new IdentityProviderException($errorMessage, $errorCode, $data);
} }
} }
protected function createResourceOwner(array $response, AccessToken $token): VkUser protected function createResourceOwner(array $response, AccessToken $token): VkUser
{ {
$response = reset($response['response']); $response = reset($response['response']);
$additional = $token->getValues(); $additional = $token->getValues();
if (!empty($additional['email'])) { if (!empty($additional['email'])) {
$response['email'] = $additional['email']; $response['email'] = $additional['email'];
} }
if (!empty($response['uid']) && 4 === floor($this->version)) {
if (!empty($response['uid']) && 4 === (int) floor($this->version)) {
$response['id'] = $response['uid']; $response['id'] = $response['uid'];
} }
if (!empty($additional['user_id'])) { if (!empty($additional['user_id'])) {
$response['id'] = $additional['user_id']; $response['id'] = $additional['user_id'];
} }
return new VkUser($response, $response['id']); return new VkUser($response);
} }
/** /**
* Возвращает массив объектов пользователей.
*
* @see https://vk.com/dev/users.get * @see https://vk.com/dev/users.get
*
* @param integer[] $ids
* @param AccessToken|null $token Current user if empty
* @param array $params
*
* @return User[]
*/ */
public function usersGet(array $ids = [], AccessToken $token = null, array $params = []): array public function usersGet(array $ids = [], ?AccessToken $token = null, array $params = []): array
{ {
if (empty($ids) && !$token) { if (empty($ids) && null === $token) {
throw new \InvalidArgumentException('Some of parameters usersIds OR access_token are required'); throw new \InvalidArgumentException('Some of parameters usersIds OR access_token are required');
} }
$default = [ $default = [
'user_ids' => implode(',', $ids), 'user_ids' => implode(',', $ids),
'fields' => $this->userFields, 'fields' => $this->userFields,
'access_token' => $token ? $token->getToken() : null, 'access_token' => null !== $token ? $token->getToken() : null,
'v' => $this->version, 'v' => $this->version,
'lang' => $this->language 'lang' => $this->language,
]; ];
$params = array_merge($default, $params); $params = array_merge($default, $params);
$query = $this->buildQueryString($params); $query = $this->buildQueryString($params);
$url = "$this->baseUri/users.get?$query"; $url = "$this->baseUri/users.get?$query";
$response = $this->getResponse($this->createRequest(static::METHOD_GET, $url, $token, []))['response']; $response = $this->getResponse($this->createRequest(static::METHOD_GET, $url, $token, []))['response'];
$users = !empty($response['items']) ? $response['items'] : $response; $users = !empty($response['items']) ? $response['items'] : $response;
$array2user = function ($userData) {
$array2user = function (mixed $userData) {
return new VkUser($userData); return new VkUser($userData);
}; };
return array_map($array2user, $users); return array_map($array2user, $users);
} }
/** /**
* Возвращает список идентификаторов (id) друзей пользователя,
* если параметр fields не использовался. При использовании
* параметра fields возвращает список объектов пользователей,
* но не более 5000.
*
* @see https://vk.com/dev/friends.get * @see https://vk.com/dev/friends.get
*
* @param integer $userId
* @param AccessToken|null $token
* @param array $params
*
* @return User[]
*/ */
public function friendsGet($userId, AccessToken $token = null, array $params = []): array public function friendsGet(int $userId, ?AccessToken $token = null, array $params = []): array
{ {
$default = [ $default = [
'user_id' => $userId, 'user_id' => $userId,
'fields' => $this->userFields, 'fields' => $this->userFields,
'access_token' => $token ? $token->getToken() : null, 'access_token' => null !== $token ? $token->getToken() : null,
'v' => $this->version, 'v' => $this->version,
'lang' => $this->language 'lang' => $this->language,
]; ];
$params = array_merge($default, $params); $params = array_merge($default, $params);
$query = $this->buildQueryString($params); $query = $this->buildQueryString($params);
$url = "$this->baseUri/friends.get?$query"; $url = "$this->baseUri/friends.get?$query";
$response = $this->getResponse($this->createRequest(static::METHOD_GET, $url, $token, []))['response']; $response = $this->getResponse($this->createRequest(static::METHOD_GET, $url, $token, []))['response'];
$friends = !empty($response['items']) ? $response['items'] : $response; $friends = !empty($response['items']) ? $response['items'] : $response;
$array2friend = function ($friendData) {
$array2friend = function (mixed $friendData) {
if (is_numeric($friendData)) { if (is_numeric($friendData)) {
$friendData = ['id' => $friendData]; $friendData = ['id' => $friendData];
} }

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Sept\OAuth2\Client\Provider; namespace Sept\OAuth2\Client\Provider;
use League\OAuth2\Client\Provider\ResourceOwnerInterface; use League\OAuth2\Client\Provider\ResourceOwnerInterface;
@@ -9,10 +11,7 @@ use League\OAuth2\Client\Provider\ResourceOwnerInterface;
*/ */
class VkUser implements ResourceOwnerInterface class VkUser implements ResourceOwnerInterface
{ {
/** protected array $response;
* @type array
*/
protected $response;
/** /**
* User constructor. * User constructor.
@@ -22,129 +21,200 @@ class VkUser implements ResourceOwnerInterface
$this->response = $response; $this->response = $response;
} }
/**
* Вернуть все поля массивом
*/
public function toArray(): array public function toArray(): array
{ {
return $this->response; return $this->response;
} }
/**
* Идентификатор пользователя.
*/
public function getId(): int public function getId(): int
{ {
return (int)($this->getField('uid') ?: $this->getField('id')); return (int) ((bool) $this->getField('uid') ? $this->getField('uid') : $this->getField('id'));
} }
/** /**
* Helper for getting user data * Helper for getting user data.
*/ */
protected function getField(string $key): mixed|null protected function getField(string $key): mixed
{ {
return !empty($this->response[$key]) ? $this->response[$key] : null; return \array_key_exists($key, $this->response) ? $this->response[$key] : null;
} }
/** /**
* Дата рождения. Возвращается в формате D.M.YYYY или D.M (если год рождения скрыт). Если дата рождения скрыта целиком, поле отсутствует в ответе.
*
* @return string|null DD.MM.YYYY * @return string|null DD.MM.YYYY
*/ */
public function getBirthday():string public function getBirthday(): ?string
{ {
return $this->getField('bdate'); return $this->getField('bdate');
} }
/** /**
* Информация о городе, указанном на странице пользователя в разделе «Контакты». Возвращаются следующие поля:
* id (integer) — идентификатор города, который можно использовать для получения его названия с помощью метода database.getCitiesById;
* title (string) — название города.
*
* @return array [id =>, title => string] * @return array [id =>, title => string]
*/ */
public function getCity(): array public function getCity(): ?array
{ {
return $this->getField('city'); return $this->getField('city');
} }
/** /**
* Информация о стране, указанной на странице пользователя в разделе «Контакты». Возвращаются следующие поля:
* id (integer) — идентификатор страны, который можно использовать для получения ее названия с помощью метода database.getCountriesById;
* title (string) — название страны.
*
* @return array [id =>, title => string] * @return array [id =>, title => string]
*/ */
public function getCountry(): array public function getCountry(): ?array
{ {
return $this->getField('country'); return $this->getField('country');
} }
/** /**
* Short address to user page * Короткий адрес страницы. Возвращается строка, содержащая короткий адрес страницы (например, andrew).
* Если он не назначен, возвращается "id"+user_id, например, id35828305.
*
* Short address to user page.
*/ */
public function getDomain(): string public function getDomain(): ?string
{ {
return $this->getField('domain'); return $this->getField('domain');
} }
public function getFirstName(): string /**
* Имя.
*/
public function getFirstName(): ?string
{ {
return $this->getField('first_name'); return $this->getField('first_name');
} }
/** /**
* Friend status.
*
* @return int 0|1|2|3 => nobody|resquest_sent|incoming_request|friends * @return int 0|1|2|3 => nobody|resquest_sent|incoming_request|friends
*/ */
public function getFriendStatus(): int public function getFriendStatus(): ?int
{ {
return $this->getField('friend_Status'); return $this->getField('friend_Status');
} }
/** /**
* Has user avatar? * Информация о том, установил ли пользователь фотографию для профиля. Возвращаемые значения: 1 — установил, 0 — не установил.
*/ */
public function isHasPhoto(): bool public function isHasPhoto(): bool
{ {
return (bool) $this->getField('has_photo'); return (bool) $this->getField('has_photo');
} }
public function getHomeTown(): string /**
* Название родного города.
*/
public function getHomeTown(): ?string
{ {
return $this->getField('home_town'); return $this->getField('home_town');
} }
/** /**
* Detect if current user is freind to this * Detect if current user is freind to this.
*/ */
public function isFriend(): bool public function isFriend(): bool
{ {
return (bool) $this->getField('is_friend'); return (bool) $this->getField('is_friend');
} }
public function getLastName(): string /**
* Фамилия.
*/
public function getLastName(): ?string
{ {
return $this->getField('last_name'); return $this->getField('last_name');
} }
public function getMaidenName(): string /**
* Девичья фамилия.
*/
public function getMaidenName(): ?string
{ {
return $this->getField('maiden_name'); return $this->getField('maiden_name');
} }
public function getNickname(): string /**
* Никнейм (отчество) пользователя.
*/
public function getNickname(): ?string
{ {
return $this->getField('nickname'); return $this->getField('nickname');
} }
/** /**
* It's square! * URL квадратной фотографии с максимальной шириной.
* Может быть возвращена фотография, имеющая ширину как 200, так и 100 пикселей.
* В случае отсутствия у пользователя фотографии возвращается https://vk.com/images/camera_200.png.
*/ */
public function getPhotoMax():string public function getPhotoMax(): ?string
{ {
return $this->getField('photo_max'); return $this->getField('photo_max');
} }
public function getPhotoMaxOrig(): string /**
* URL фотографии максимального размера. Может быть возвращена фотография,
* имеющая ширину как 400, так и 200 пикселей.
* В случае отсутствия у пользователя фотографии возвращается https://vk.com/images/camera_400.png.
*/
public function getPhotoMaxOrig(): ?string
{ {
return $this->getField('photo_max_orig'); return $this->getField('photo_max_orig');
} }
public function getScreenName(): string /**
* Короткое имя страницы.
*/
public function getScreenName(): ?string
{ {
return $this->getField('screen_name'); return $this->getField('screen_name');
} }
public function getSex(): int /**
* Пол. Возможные значения
* 1 — женский;
* 2 — мужской;
* 0 — пол не указан.
*/
public function getSex(): ?int
{ {
return $this->getField('sex'); return $this->getField('sex');
} }
public function getEmail(): string public function getEmail(): ?string
{ {
return $this->getField('email'); return $this->getField('email');
} }
/**
* Поле возвращается, если страница пользователя удалена или заблокирована, содержит значение deleted или banned. В этом случае опциональные поля не возвращаются.
*
* @return string null|deleted|banned
*/
public function getDeactivated(): ?string
{
return $this->getField('deactivated');
}
/**
* Скрыт ли профиль пользователя настройками приватности.
*/
public function isClosed(): bool
{
return $this->getField('is_closed');
}
} }