Completed
Push — master ( 6fcdef...a31999 )
by Francis
01:25
created

GMail::getLastResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
declare(strict_types=1);
3
defined('BASEPATH') OR exit('No direct script access allowed');
4
5
class GMail {
6
7
  const AUTH_URL  = 'https://accounts.google.com/o/oauth2/auth';
8
  const TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
9
  const API       = 'https://www.googleapis.com/gmail/v1/users/';
10
  const HTTP_CODE = 'http_code';
11
  const PACKAGE   = 'francis94c/ci-gmail';
12
  private $clientId;
13
  private $clientSecret;
14
  private $redirectUri = 'urn:ietf:wg:oauth:2.0:oob';
15
  private $token;
16
  private $userAgent = 'CodeIgniter GMail API';
17
  private $lastResponse;
18
  private $lastResponseCode;
19
20
  function __construct($params=null)
21
  {
22
    get_instance()->load->splint('francis94c/ci-gmail', '%curl');
0 ignored issues
show
Bug introduced by
The function get_instance was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

22
    /** @scrutinizer ignore-call */ 
23
    get_instance()->load->splint('francis94c/ci-gmail', '%curl');
Loading history...
23
    get_instance()->load->splint('francis94c/ci-gmail', '%base64');
24
25
    if ($params != null) $this->init($params);
26
27
    spl_autoload_register(function($name) {
28
      if (file_exists(APPPATH.'splints/'.self::PACKAGE."/libraries/$name.php")) {
0 ignored issues
show
Bug introduced by
The constant APPPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
29
        require(APPPATH.'splints/'.self::PACKAGE."/libraries/$name.php");
30
      }
31
    });
32
  }
33
34
  /**
35
   * [init Initialize library with cofigs. Can be called multiple times to set
36
   *       config items]
37
   * @param array $config Associative Config Array.
38
   */
39
  public function init(array $config):void {
40
    $this->clientId = $config['client_id'] ?? $this->clientId;
41
    $this->clientSecret = $config['client_secret'] ?? $this->clientSecret;
42
    $this->redirectUri = $config['redirect_uri'] ?? $this->redirectUri;
43
  }
44
  /**
45
   * [setAccessToken description]
46
   * @param string $token [description]
47
   */
48
  public function setAccessToken(string $token):void {
49
    $this->token = $token;
50
  }
51
  /**
52
   * [getClientId Get Client ID.]
53
   * @return null|string Client ID.
54
   */
55
  public function getClientId():?string {
56
    return $this->clientId;
57
  }
58
  /**
59
   * [getAuthorizeUrl Gets/composes the authorize url to direct users to so they
60
   *                  can give your application access to their GMail accounts
61
   *                  based on the given scopes.]
62
   * @param  string $scope        Access Scope.
63
   * @param  string $redirectUri  URL to redirect to after access is granted.
64
   * @param  string $responseType Response type. 'code' by default.
65
   * @param  bool   $prompt       Add the prompt=consent query to the URL.
66
   * @return string               Authorize URL
67
   */
68
  public function getAuthorizeUrl(string $scope, string $redirectUri=null,
69
  string $responseType='code', string $accessType='offline', bool $prompt=false):string
70
  {
71
    $redirectUri = $redirectUri ?? $this->redirectUri;
72
    if ($scope == null) throw new Exception("GMail scope cannot be null");
73
    $params = [
74
      'client_id'     => $this->clientId,
75
      'redirect_uri'  => $redirectUri,
76
      'scope'         => $scope,
77
      'response_type' => $responseType,
78
      'access_type'   => $accessType
79
    ];
80
    if ($prompt) $params['prompt'] = 'consent';
81
    return self::AUTH_URL . build_url_query($params, false);
82
  }
83
  /**
84
   * [getToken description]
85
   * @param  string $code [description]
86
   * @return [type]       [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
87
   */
88
  public function getToken(string $code, string $redirectUri=null):?object
89
  {
90
    $redirectUri = $redirectUri ?? $this->redirectUri;
0 ignored issues
show
Unused Code introduced by
The assignment to $redirectUri is dead and can be removed.
Loading history...
91
    $ch = curl_init(self::TOKEN_URL);
92
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
    curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_RETURNTRANSFER, true);
Loading history...
93
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
94
    if (ENVIRONMENT == 'development') {
0 ignored issues
show
Bug introduced by
The constant ENVIRONMENT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
95
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
96
    }
97
    $body = http_build_query([
98
      'code'          => $code,
99
      'client_id'     => $this->clientId,
100
      'client_secret' => $this->clientSecret,
101
      'redirect_uri'  => $this->redirectUri,
102
      'grant_type'    => 'authorization_code'
103
    ]);
104
    $header = [
105
      'Content-Type: application/x-www-form-urlencoded',
106
      'Content-Length: ' . strlen($body)
107
    ];
108
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
109
    curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
110
    // Request Method and Body.
111
    curl_setopt($ch, CURLOPT_POST, true);
112
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
113
    $response = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

113
    $response = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
114
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_getinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

114
    $code = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
115
    curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

115
    curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
116
    $this->lastResponse = $response;
117
    $this->lastResponseCode = $code;
118
    if ($response !== false) return $this->process_response($code, $response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $response of GMail::process_response() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
    if ($response !== false) return $this->process_response($code, /** @scrutinizer ignore-type */ $response);
Loading history...
119
    return null;
120
  }
121
  /**
122
   * [refreshAccessToken description]
123
   * @param  string $refreshToken [description]
124
   * @return [type]               [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
125
   */
126
  public function refreshAccessToken(string $refreshToken):?object
127
  {
128
    $ch = curl_init(self::TOKEN_URL);
129
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
    curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_RETURNTRANSFER, true);
Loading history...
130
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
131
    if (ENVIRONMENT == 'development') {
0 ignored issues
show
Bug introduced by
The constant ENVIRONMENT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
132
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
133
    }
134
    $body = http_build_query([
135
      'refresh_token' => $refreshToken,
136
      'client_id'     => $this->clientId,
137
      'client_secret' => $this->clientSecret,
138
      'grant_type'    => 'refresh_token'
139
    ]);
140
    $header = [
141
      'Content-Type: application/x-www-form-urlencoded',
142
      'Content-Length: ' . strlen($body)
143
    ];
144
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
145
    curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
146
    // Request Method and Body.
147
    curl_setopt($ch, CURLOPT_POST, true);
148
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
149
    // Exec.
150
    $response = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
    $response = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
151
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_getinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

151
    $code = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
152
    curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
    curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
153
    $this->lastResponse = $response;
154
    $this->lastResponseCode = $code;
155
    if ($response !== false) return $this->process_response($code, $response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $response of GMail::process_response() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
    if ($response !== false) return $this->process_response($code, /** @scrutinizer ignore-type */ $response);
Loading history...
156
    return null;
157
  }
158
  /**
159
   * [getProfile Get user's profile
160
   * see https://developers.google.com/gmail/api/v1/reference/users/getProfile]
161
   * @param  string $user [description]
162
   * @return [type]       [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
163
   */
164
  public function getProfile(string $user='me'):?object
165
  {
166
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
167
      self::API . "$user/profile",
168
      ["Authorization: Bearer $this->token"]
169
    );
170
    $this->lastResponse = $response;
171
    $this->lastResponseCode = $code;
172
    if ($response !== false) return $this->process_response($code, $response);
173
    return null;
174
  }
175
176
  /**
177
   * [watch Causes push notifications to be sent on events which occur in the
178
   * user's mailbox. Requires Google Cloud PubSub.
179
   * see https://developers.google.com/gmail/api/v1/reference/users/watch]
180
   * @param  string $topic             Topic to push events to.
181
   * @param  mixed  $labelIds          Narrow down labels in the mailbox, whose
182
   *                                   mailbox event, are being listened to.
183
   *                                   events are to be listened to.
184
   * @param  string $userId            The ID/Email address of the user.
185
   * @param  string $labelFilterAction [description]
186
   * @return [type]                    [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
187
   */
188
  public function watch(string $topic, $labelIds=null, string $userId='me',
189
  string $labelFilterAction='include'):?object
190
  {
191
    $body = [
192
      'topicName'         => $topic,
193
      'labelFilterAction' => $labelFilterAction
194
    ];
195
196
    if ($labelIds != null) {
197
      if (is_scalar($labelIds)) {
198
        $body['labelIds'] = [$labelIds];
199
      } elseif (is_array($labelIds)) {
200
        $body['labelIds'] = $labelIds;
201
      }
202
    }
203
204
    list($code, $response) = (new GMailCURL(GMailCURL::POST))(
205
      self::API . "$userId/watch",
206
      ["Authorization: Bearer $this->token"],
207
      $body
208
    );
209
    $this->lastResponse = $response;
210
    $this->lastResponseCode = $code;
211
    if ($response !== false) return $this->process_response($code, $response);
212
    return null;
213
  }
214
215
  /**
216
   * [endWatch stop watch operations on given email ID]
217
   * @date   2019-11-20
218
   * @param  string     $userId ID or Email Address of the user.
219
   * @return bool               [description]
220
   */
221
  public function endWatch(string $userId='me'):bool
222
  {
223
    list($code, $response) = (new GMailCURL(GMailCURL::POST))(
224
      self::API . "$userId/stop",
225
      ["Authorization: Bearer $this->token"]
226
    );
227
    $this->lastResponse = $response;
228
    $this->lastResponseCode = $code;
229
    if ($response !== false) return $code == 204;
230
    return false;
231
  }
232
233
  /**
234
   * [getLabels description]
235
   * @date   2019-11-20
236
   * @param  string     $userID [description]
237
   * @return null|array         [description]
238
   */
239
  public function getLabels(string $userId='me'):?object
240
  {
241
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
242
      self::API . "$userId/labels",
243
      ["Authorization: Bearer $this->token"]
244
    );
245
    $this->lastResponse = $response;
246
    $this->lastResponseCode = $code;
247
    if ($response !== false) {
248
      return json_decode($response)->labels;
249
    }
250
    return null;
251
  }
252
  /**
253
   * [getMessages description]
254
   * @date   2019-11-21
255
   * @param  string     $userId           [description]
256
   * @param  [type]     $labelIds         [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
257
   * @param  [type]     $q                [description]
258
   * @param  [type]     $maxMessages      [description]
259
   * @param  [type]     $pageToken        [description]
260
   * @param  boolean    $includeSpamTrash [description]
261
   * @param  [type]     $truncateAfter    [description]
262
   * @return [type]                       [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
263
   */
264
  public function getMessages(string $userId='me', array $labelIds=null,
265
  string $q=null, int $maxMessages=null, string $pageToken=null, bool $includeSpamTrash=false,
266
  $truncateAfter=null):?object
267
  {
268
    $query = [];
269
270
    if ($labelIds != null) $query['labelIds'] = $labelIds;
271
    if ($includeSpamTrash) $query['includeSpamTrash'] = $includeSpamTrash;
272
    if ($q != null) $query['q'] = $q;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $q of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
273
    if ($pageToken != null) $query['pageToken'] = $pageToken;
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $pageToken of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
274
    if ($maxMessages != null) $query['maxResults'] = $maxMessages;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $maxMessages of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
275
276
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
277
      self::API . "$userId/messages" . build_url_query($query),
278
      ["Authorization: Bearer $this->token"]
279
    );
280
281
    $this->lastResponse = $response;
282
    $this->lastResponseCode = $code;
283
284
    if ($response !== false) {
285
      if ($truncateAfter != null && $code == 200) {
286
        $response = json_decode($response);
287
        $response->messages = array_filter($response->messages, function ($e) use ($truncateAfter) {
288
          return strcmp($truncateAfter, $e->id) < 0;
289
        });
290
        $response->{self::HTTP_CODE} = $code;
291
        return $response;
292
      }
293
294
      return $this->process_response($code, $response);
295
    }
296
297
    return null;
298
  }
299
  /**
300
   * [getMessage description]
301
   * @date   2019-11-21
302
   * @param  string       $userId          [description]
303
   * @param  string       $messageId       [description]
304
   * @param  string       $format          [description]
305
   * @param  [type]       $metadataHeaders [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
306
   * @return Message|null                  [description]
307
   */
308
  public function getMessage(string $userId='me', string $messageId,
309
  string $format='full', array $metadataHeaders=null):?Message
310
  {
311
    $query = [];
312
313
    if ($format != 'full' && $format != null) $query['format'] = $format;
314
    if ($metadataHeaders != null) $query['metadataHeaders'] = $metadataHeaders;
315
316
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
317
      self::API . "$userId/messages/$messageId?" . http_build_query($query),
318
      ["Authorization: Bearer $this->token"]
319
    );
320
321
    $this->lastResponse = $response;
322
    $this->lastResponseCode = $code;
323
324
    if ($response !== false) return new Message($response);
325
326
    return null;
327
  }
328
329
  /**
330
   * [getLastResponse description]
331
   * @date   2020-03-07
332
   * @return string     [description]
333
   */
334
  public function getLastResponse():string
335
  {
336
    return $this->lastResponse;
337
  }
338
339
  /**
340
   * [getLastResponseCode description]
341
   * @date   2020-03-07
342
   * @return int        [description]
343
   */
344
  public function getLastResponseCode():int
345
  {
346
    return $this->lastResponseCode;
347
  }
348
  
349
  /**
350
   * [process_response description]
351
   * @param  int    $code     [description]
352
   * @param  string $response [description]
353
   * @return [type]           [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
354
   */
355
  private function process_response(int $code, string $response):?object {
356
    $response = json_decode($response);
357
    $response->{self::HTTP_CODE} = $code;
358
    return $response;
359
  }
360
}
361