VKBase::setAPIVersion()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace FreedomCore\VK;
4
5
use FreedomCore\VK\API\VKAccount;
6
use FreedomCore\VK\API\VKUsers;
7
8
class VKBase {
9
10
    /**
11
     * Application ID
12
     * @var string
13
     */
14
    private $applicationID;
15
16
    /**
17
     * Application Secret Key
18
     * @var string
19
     */
20
    private $APISecret;
21
22
    /**
23
     * API Version. If null, uses latest available version
24
     * @var string
25
     */
26
    private $APIVersion;
27
28
    /**
29
     * Acess Token String
30
     * @var string
31
     */
32
    private $accessToken;
33
34
    /**
35
     * Authorization Status
36
     * @var bool
37
     */
38
    private $authorizationStatus = false;
39
40
    /**
41
     * CURL Object
42
     * @var Resource
43
     */
44
    private $curlObject;
45
46
    /**
47
     * Users Access Permissions
48
     * @var int
49
     */
50
    private $permissionsMask = 0;
51
52
    /**
53
     * Determine if permissions mask is set
54
     * @var bool
55
     */
56
    private $isPermissionsMaskSet = false;
57
58
    /**
59
     * URL For Authorization
60
     */
61
    const AUTHORIZATION_URL = 'https://oauth.vk.com/authorize';
62
63
    /**
64
     * URL For Access Token
65
     */
66
    const ACCESS_TOKEN_URL = 'https://oauth.vk.com/access_token';
67
68
    /**
69
     * URL For VK API
70
     */
71
    const METHOD_URL = 'https://api.vk.com/method/';
72
73
    /**
74
     * URL For OAuth Token
75
     */
76
    const TOKEN_URL = 'https://oauth.vk.com/token';
77
78
    const DEFAULT_CALLBACK = 'https://api.vk.com/blank.html';
79
80
    const PACKAGE_VERSION = '1.0.5';
81
82
    /**
83
     * VK constructor.
84
     * @param string $appID
85
     * @param string $apiSecret
86
     * @param string $accessToken
87
     * @throws VKException
88
     */
89
    public function __construct($appID, $apiSecret, $accessToken = null) {
90
        $this->applicationID = $appID;
91
        $this->APISecret = $apiSecret;
92
        $this->accessToken = $accessToken;
93
        $this->curlObject = curl_init();
94
        if (!is_null($accessToken)) {
95
            if (!$this->isPermissionsMaskSet) {
96
                $VKUser = new VKUsers($this);
97
                $VKAccount = new VKAccount($this);
98
                $CurrentUser = $VKUser->get([ '' ])[ 'response' ][ 0 ][ 'uid' ];
99
                $this->setPermissionsMask($VKAccount->getAppPermissions($CurrentUser)[ 'response' ]);
100
                $this->isPermissionsMaskSet = true;
101
                unset($VKUser);
102
                unset($VKAccount);
103
            }
104
        }
105
    }
106
107
    /**
108
     * VK destructor.
109
     */
110
    public function __destruct() {
111
        curl_close($this->curlObject);
112
    }
113
114
    /**
115
     * Set API Version Provided By User
116
     * @param int $apiVersion
117
     */
118
    public function setAPIVersion($apiVersion) {
119
        $this->APIVersion = $apiVersion;
0 ignored issues
show
Documentation Bug introduced by
The property $APIVersion was declared of type string, but $apiVersion is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
120
    }
121
122
    /**
123
     * Returns Base API URL
124
     * @param string $apiMethod
125
     * @param string $responseFormat
126
     * @return string
127
     */
128
    public function getAPIUrl($apiMethod, $responseFormat = 'json') {
129
        return self::METHOD_URL . $apiMethod.'.'.$responseFormat;
130
    }
131
132
    /**
133
     * Returns Authorization Link With Passed Parameters
134
     * @param string $apiSettings
135
     * @param string $callbackURL
136
     * @param string $responseType
137
     * @param bool $testMode
138
     * @return string
139
     */
140
    public function getAuthorizationURL($apiSettings = '', $callbackURL = self::DEFAULT_CALLBACK, $responseType = 'code', $testMode = false) {
141
        $allowedTypes = [ 'token', 'code' ];
142
        $requestParameters = [
143
            'client_id'     =>  $this->applicationID,
144
            'scope'         =>  $apiSettings,
145
            'redirect_uri'  =>  $callbackURL,
146
            'response_type' =>  (in_array($responseType, $allowedTypes)) ? $responseType : 'code'
147
        ];
148
149
        if ($testMode) {
150
            $requestParameters[ 'test_mode' ] = 1;
151
        }
152
153
        return $this->createURL(self::AUTHORIZATION_URL, $requestParameters);
154
    }
155
156
    /**
157
     * Returns Access Token From Authorization Link
158
     * @param $resultCode
159
     * @param string $callbackURL
160
     * @return mixed
161
     * @throws VKException
162
     */
163
    public function getAccessToken($resultCode, $callbackURL = self::DEFAULT_CALLBACK) {
164
        if (!is_null($this->accessToken) && $this->authorizationStatus) {
165
            throw new VKException('Already Authorized!', 1);
166
        }
167
168
        $requestParameters = [
169
            'client_id'     => $this->applicationID,
170
            'client_secret' =>  $this->APISecret,
171
            'redirect_uri'  =>  $callbackURL,
172
            'code'          =>  $resultCode
173
        ];
174
175
        $apiResponse = json_decode($this->performRequest($this->createURL(self::ACCESS_TOKEN_URL, $requestParameters)), true);
176
177
        try {
178
            if (isset($apiResponse[ 'error' ])) {
179
                throw new VKException($apiResponse[ 'error' ].(!isset($apiResponse[ 'error_description' ]) ?: ': '.$apiResponse[ 'error_description' ]), '0');
180
            } else {
181
                $this->authorizationStatus = true;
182
                $this->accessToken = $apiResponse[ 'access_token' ];
183
                return $apiResponse;
184
            }
185
        } catch (VKException $ex) {
186
            echo $ex->getMessage();
187
            return [ ];
188
        }
189
    }
190
191
    /**
192
     * Returns User Authorization Status
193
     * @return bool
194
     */
195
    public function isAuthorized() {
196
        return !is_null($this->accessToken);
197
    }
198
199
200
    /**
201
     * Execute API Method With Parameters and return Result
202
     * @param string $apiMethod
203
     * @param array $requestParameters
204
     * @param string $resultType
205
     * @param string $requestMethod
206
     * @return mixed
207
     */
208
    public function apiQuery($apiMethod, $requestParameters = [ ], $resultType = 'array', $requestMethod = 'get') {
209
        $requestParameters[ 'timestamp' ] = time();
210
        $requestParameters[ 'api_id' ]    = $this->applicationID;
211
        $requestParameters[ 'random' ]    = rand(0, 10000);
212
213
        if (!array_key_exists('access_token', $requestParameters) && !is_null($this->accessToken)) {
214
            $requestParameters[ 'access_token' ] = $this->accessToken;
215
        }
216
217
        if (!array_key_exists('v', $requestParameters) && !is_null($this->APIVersion)) {
218
            $requestParameters[ 'v' ] = $this->APIVersion;
219
        }
220
221
        ksort($requestParameters);
222
223
        $parametersSignature = '';
224
        foreach ($requestParameters as $pKey=>$pValue) {
225
            if (is_array($pValue)) {
226
                $pValue = implode(', ', $pValue);
227
            }
228
            $parametersSignature .= $pKey . '=' . $pValue;
229
        }
230
        $parametersSignature .= $this->APISecret;
231
232
        $requestParameters[ 'sig' ] = md5($parametersSignature);
233
234
        if ($apiMethod == 'execute' || $requestMethod == 'post') {
235
            $apiResponse = $this->performRequest($this->getAPIUrl($apiMethod, $resultType == 'array' ? 'json' : $resultType), "POST", $requestParameters);
236
        } else {
237
            $apiResponse = $this->performRequest($this->createURL($this->getAPIUrl($apiMethod, $resultType == 'array' ? 'json' : $resultType), $requestParameters));
238
        }
239
240
        try {
241
            $decodedJSON = json_decode($apiResponse, true);
242
            if (isset($decodedJSON[ 'error' ])) {
243
                throw new VKException($decodedJSON[ 'error' ][ 'error_msg' ], $decodedJSON[ 'error' ][ 'error_code' ], $decodedJSON[ 'error' ][ 'request_params' ]);
244
            }
245
246
            return $resultType == 'array' ? $decodedJSON : $apiResponse;
247
        } catch(VKException $ex) {
248
            echo $ex->getMessage();
249
            return [ ];
250
        }
251
    }
252
253
    /**
254
     * Set Permissions Mask
255
     * @param int $permMask
256
     */
257
    public function setPermissionsMask($permMask) {
258
        $this->permissionsMask = $permMask;
259
    }
260
261
    /**
262
     * Get Permissions Mask
263
     * @return int
264
     */
265
    public function getPermissionsMask() {
266
        return $this->permissionsMask;
267
    }
268
269
    /**
270
     * Concatenate Keys And Values Of Parameters Array And Return URL String
271
     * @param string $urlString
272
     * @param array $parametersArray
273
     * @return string
274
     */
275
    private function createURL($urlString, $parametersArray) {
276
        $urlString .= '?' . http_build_query($parametersArray);
277
        return $urlString;
278
    }
279
280
    /**
281
     * Execute Request
282
     * @param string $requestURL
283
     * @param string $requestMethod
284
     * @param array $postFields
285
     * @return string
286
     */
287
    private function performRequest($requestURL, $requestMethod = 'GET', $postFields = [ ]) {
288
        curl_setopt_array($this->curlObject, [
289
            CURLOPT_USERAGENT       =>  'FreedomCore/' . self::PACKAGE_VERSION . ' VK OAuth Client',
290
            CURLOPT_RETURNTRANSFER  => true,
291
            CURLOPT_SSL_VERIFYPEER  => false,
292
            CURLOPT_POST            => ($requestMethod == 'POST'),
293
            CURLOPT_POSTFIELDS      => $postFields,
294
            CURLOPT_URL             => $requestURL
295
        ]);
296
297
        return curl_exec($this->curlObject);
298
    }
299
300
}
301
302
/**
303
 * Class VKException
304
 * @package FreedomCore\VK
305
 */
306
class VKException extends \Exception {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
307
308
    /**
309
     * VKException constructor.
310
     * @param string $message
311
     * @param int $code
312
     * @param null $parameters
313
     */
314
    public function __construct($message, $code, $parameters = null) {
315
        $Message = '<h1>API Request Error!</h1>';
316
        $Message .= '<table width="100%">';
317
318
        $Message .= '<tr><td width="10%"><strong>Error Code:</strong></td> <td>'.$code.'</td></tr>';
319
        $APIError = $this->codeToErrorText($code);
320
        $Message .= '<tr><td width="10%"><strong>API Message:</strong></td> <td>'.$APIError[ 'title' ].' <span style="color: gray;">('.$APIError[ 'description' ].')</span></td></tr>';
321
        $Message .= '<tr><td width="10%"><strong>Error Message:</strong></td> <td>'.$message.'</td></tr>';
322
        if ($parameters != null && is_array($parameters)) {
323
            $Message .= '<tr><td width="10%"><strong>Request Parameters:</strong></td> <td>';
324
325
            $Message .= '<table width="15%">';
326
            foreach ($parameters as $parameter) {
327
                $Message .= "<tr><td><strong>".$parameter[ 'key' ]."</strong></td><td width='15%'>=></td><td>".$parameter[ 'value' ]."</td></tr>";
328
            }
329
            $Message .= '</table>';
330
            $Message .= '</td></tr>';
331
        }
332
333
        $Message .= '</table>';
334
        parent::__construct($Message, $code);
335
    }
336
337
    /**
338
     * Convert INT Code To Full Description
339
     * @param int $Code
340
     * @return mixed
341
     */
342
    private function codeToErrorText($Code) {
343
        $errorsData = [
344
            1       =>  [ 'title' => 'Unknown error occurred',  'description' => 'Try again later.' ],
345
            2       =>  [ 'title' => 'Application is disabled. Enable your application or use test mode ',  'description' => 'You need to switch on the app in Settings (https://vk.com/editapp?id={Your API_ID} or use the test mode (test_mode=1).' ],
346
            3       =>  [ 'title' => 'Unknown method passed ',  'description' => 'Check the method name: <a href="http://vk.com/dev/methods" target="_blank">http://vk.com/dev/methods</a> ' ],
347
            4       =>  [ 'title' => 'Incorrect signature ',  'description' => 'Check if the signature has been formed correctly: <a href="https://vk.com/dev/api_nohttps" target="_blank"></a>' ],
348
            5       =>  [ 'title' => 'User authorization failed ',  'description' => 'Make sure that you use a correct authorization type. To work with the methods without a secureprefix you need to authorize a user with one of these ways:  http://vk.com/dev/auth_sites, http://vk.com/dev/auth_mobile.' ],
349
            6       =>  [ 'title' => 'Too many requests per second ',  'description' => 'Decrease the request frequency or use the execute method. More details on frequency limits here: <a href="http://vk.com/dev/api_requests" target="_blank">http://vk.com/dev/api_requests</a>' ],
350
            7       =>  [ 'title' => 'Permission to perform this action is denied ',  'description' => 'Make sure that your have received required permissions during the authorization. You can do it with the account.getAppPermissions method.' ],
351
            8       =>  [ 'title' => 'Invalid request ',  'description' => 'Check the request syntax and used parameters list (it can be found on a method description page) ' ],
352
            9       =>  [ 'title' => 'Flood control ',  'description' => 'You need to decrease the count of identical requests. For more efficient work you may use execute or JSONP.' ],
353
            10      =>  [ 'title' => 'Internal server error',  'description' => 'Try again later.' ],
354
            11      =>  [ 'title' => 'In test mode application should be disabled or user should be authorized',  'description' => 'Switch the app off in Settings: https://vk.com/editapp?id={Your API_ID}.' ],
355
            14      =>  [ 'title' => 'Captcha needed ',  'description' => 'Work with this error is explained in detail on the <a href="https://vk.com/dev/need_confirmation" target="_blank">separate page</a>' ],
356
            15      =>  [ 'title' => 'Access denied ',  'description' => 'Make sure that you use correct identifiers and the content is available for the user in the full version of the site.' ],
357
            16      =>  [ 'title' => 'HTTP authorization failed',  'description' => 'To avoid this error check if a user has the \'Use secure connection\' option enabled with the account.getInfo method.' ],
358
            17      =>  [ 'title' => 'Validation required ',  'description' => 'Make sure that you don\'t use a token received with http://vk.com/dev/auth_mobile for a request from the server. It\'s restricted. The validation process is described on the <a href="https://vk.com/dev/need_confirmation" target="_blank">separate page</a>.' ],
359
            20      =>  [ 'title' => 'Permission to perform this action is denied for non-standalone applications ',  'description' => 'If you see this error despite your app has the Standalone type, make sure that you use redirect_uri=https://oauth.vk.com/blank.html. Details here: http://vk.com/dev/auth_mobile.' ],
360
            21      =>  [ 'title' => 'Permission to perform this action is allowed only for Standalone and OpenAPI applications',  'description' => '' ],
361
            23      =>  [ 'title' => 'This method was disabled ',  'description' => 'All the methods available now are listed here: <a href="http://vk.com/dev/methods" target="_blank">http://vk.com/dev/methods</a>' ],
362
            24      =>  [ 'title' => 'Confirmation required ',  'description' => 'Confirmation process is described on the <a href="https://vk.com/dev/need_confirmation" target="_blank">separate page</a>' ],
363
            100     =>  [ 'title' => 'One of the parameters specified was missing or invalid ',  'description' => 'Check the required parameters list and their format on a method description page.' ],
364
            101     =>  [ 'title' => 'Invalid application API ID ',  'description' => 'Find the app in the administrated list in settings: <a href="http://vk.com/apps?act=settings" target="_blank">http://vk.com/apps?act=settings</a> And set the correct API_ID in the request.' ],
365
            103     =>  [ 'title' => 'Out of limits', 'description' => 'Out of limits' ],
366
            104     =>  [ 'title' => 'Not found', 'description' => 'Not found' ],
367
            113     =>  [ 'title' => 'Invalid user id ',  'description' => 'Make sure that you use a correct id. You can get an id using a screen name with the utils.resolveScreenName method' ],
368
            150     =>  [ 'title' => 'Invalid timestamp ',  'description' => 'You may get a correct value with the utils.getServerTime method.' ],
369
            200     =>  [ 'title' => 'Access to album denied ',  'description' => 'Make sure you use correct ids (owner_id is always positive for users, negative for communities) and the current user has access to the requested content in the full version of the site.' ],
370
            201     =>  [ 'title' => 'Access to audio denied ',  'description' => 'Make sure you use correct ids (owner_id is always positive for users, negative for communities) and the current user has access to the requested content in the full version of the site.' ],
371
            203     =>  [ 'title' => 'Access to group denied ',  'description' => 'Make sure that the current user is a member or admin of the community (for closed and private groups and events).' ],
372
            300     =>  [ 'title' => 'This album is full ',  'description' => 'You need to delete the odd objects from the album or use another album.' ],
373
            500     =>  [ 'title' => 'Permission denied. You must enable votes processing in application settings',  'description' => 'Check the app settings: http://vk.com/editapp?id={Your API_ID}&section=payments' ],
374
            600     =>  [ 'title' => 'Permission denied. You have no access to operations specified with given object(s)',  'description' => '' ],
375
            603     =>  [ 'title' => 'Some ads error occurred',  'description' => '' ],
376
            1260    =>  [ 'title' => 'Invalid screen name',  'description' => 'This screen name is already in use or invalid' ],
377
        ];
378
379
        return (!array_key_exists($Code, $errorsData)) ? $errorsData[1] : $errorsData[$Code];
380
    }
381
382
}