Passed
Push — master ( 4bd253...f10fb0 )
by Francis
01:23
created

GMail::getEmails()   B

Complexity

Conditions 9
Paths 96

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 18
c 1
b 0
f 0
dl 0
loc 31
rs 8.0555
cc 9
nc 96
nop 7
1
<?php
2
declare(strict_types=1);
3
defined('BASEPATH') OR exit('No direct script access allowed');
4
5
require_once('GMailScopes.php');
6
require_once('GMailUtil.php');
7
8
class GMail {
9
10
  const AUTH_URL  = 'https://accounts.google.com/o/oauth2/auth';
11
  const TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
12
  const API       = 'https://www.googleapis.com/gmail/v1/users/';
13
  const HTTP_CODE = 'http_code';
14
  private $clientId;
15
  private $clientSecret;
16
  private $redirectUri = 'urn:ietf:wg:oauth:2.0:oob';
17
  private $token;
18
  private $userAgent = 'CodeIgniter GMail API';
19
20
  function __construct($params=null) {
21
    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

21
    /** @scrutinizer ignore-call */ 
22
    get_instance()->load->splint('francis94c/ci-gmail', '%curl');
Loading history...
22
    if ($params != null) $this->init($params);
23
  }
24
25
  /**
26
   * [init Initialize library with cofigs. Can be called multiple times to set
27
   *       config items]
28
   * @param array $config Associative Config Array.
29
   */
30
  public function init(array $config):void {
31
    $this->clientId = $config['client_id'] ?? $this->clientId;
32
    $this->clientSecret = $config['client_secret'] ?? $this->clientSecret;
33
    $this->redirectUri = $config['redirect_uri'] ?? $this->redirectUri;
34
  }
35
  /**
36
   * [setAccessToken description]
37
   * @param string $token [description]
38
   */
39
  public function setAccessToken(string $token):void {
40
    $this->token = $token;
41
  }
42
  /**
43
   * [getClientId Get Client ID.]
44
   * @return null|string Client ID.
45
   */
46
  public function getClientId():?string {
47
    return $this->clientId;
48
  }
49
  /**
50
   * [getAuthorizeUrl Gets/composes the authorize url to direct users to so they
51
   *                  can give your application access to their GMail accounts
52
   *                  based on the given scopes.]
53
   * @param  string $scope        Access Scope.
54
   * @param  string $redirectUri  URL to redirect to after access is granted.
55
   * @param  string $responseType Response type. 'code' by default.
56
   * @param  bool   $prompt       Add the prompt=consent query to the URL.
57
   * @return string               Authorize URL
58
   */
59
  public function getAuthorizeUrl(string $scope, string $redirectUri=null, string $responseType='code', string $accessType='offline', bool $prompt=false):string
60
  {
61
    $redirectUri = $redirectUri ?? $this->redirectUri;
62
    if ($scope == null) throw new Exception("GMail scope cannot be null");
63
    $params = [
64
      'client_id'     => $this->clientId,
65
      'redirect_uri'  => $redirectUri,
66
      'scope'         => $scope,
67
      'response_type' => $responseType,
68
      'access_type'   => $accessType
69
    ];
70
    if ($prompt) $params['prompt'] = 'consent';
71
    return self::AUTH_URL . build_url_query($params, false);
72
  }
73
  /**
74
   * [getToken description]
75
   * @param  string $code [description]
76
   * @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...
77
   */
78
  public function getToken(string $code, string $redirectUri=null):?array
79
  {
80
    $redirectUri = $redirectUri ?? $this->redirectUri;
0 ignored issues
show
Unused Code introduced by
The assignment to $redirectUri is dead and can be removed.
Loading history...
81
    $ch = curl_init(self::TOKEN_URL);
82
    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

82
    curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_RETURNTRANSFER, true);
Loading history...
83
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
84
    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...
85
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
86
    }
87
    $body = http_build_query([
88
      'code'          => $code,
89
      'client_id'     => $this->clientId,
90
      'client_secret' => $this->clientSecret,
91
      'redirect_uri'  => $this->redirectUri,
92
      'grant_type'    => 'authorization_code'
93
    ]);
94
    $header = [
95
      'Content-Type: application/x-www-form-urlencoded',
96
      'Content-Length: ' . strlen($body)
97
    ];
98
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
99
    curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
100
    // Request Method and Body.
101
    curl_setopt($ch, CURLOPT_POST, true);
102
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
103
    $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

103
    $response = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
104
    $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

104
    $code = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
105
    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

105
    curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
106
    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

106
    if ($response !== false) return $this->process_response($code, /** @scrutinizer ignore-type */ $response);
Loading history...
107
    return null;
108
  }
109
  /**
110
   * [refreshAccessToken description]
111
   * @param  string $refreshToken [description]
112
   * @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...
113
   */
114
  public function refreshAccessToken(string $refreshToken):?array {
115
    $ch = curl_init(self::TOKEN_URL);
116
    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

116
    curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_RETURNTRANSFER, true);
Loading history...
117
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
118
    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...
119
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
120
    }
121
    $body = http_build_query([
122
      'refresh_token' => $refreshToken,
123
      'client_id'     => $this->clientId,
124
      'client_secret' => $this->clientSecret,
125
      'grant_type'    => 'refresh_token'
126
    ]);
127
    $header = [
128
      'Content-Type: application/x-www-form-urlencoded',
129
      'Content-Length: ' . strlen($body)
130
    ];
131
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
132
    curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
133
    // Request Method and Body.
134
    curl_setopt($ch, CURLOPT_POST, true);
135
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
136
    // Exec.
137
    $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

137
    $response = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
138
    $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

138
    $code = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
139
    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

139
    curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
140
    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

140
    if ($response !== false) return $this->process_response($code, /** @scrutinizer ignore-type */ $response);
Loading history...
141
    return null;
142
  }
143
  /**
144
   * [getProfile Get user's profile
145
   * see https://developers.google.com/gmail/api/v1/reference/users/getProfile]
146
   * @param  string $user [description]
147
   * @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...
148
   */
149
  public function getProfile(string $user='me'):?array {
150
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
151
      self::API . "$user/profile",
152
      ["Authorization: Bearer $this->token"]
153
    );
154
    if ($response !== false) return $this->process_response($code, $response);
155
    return null;
156
  }
157
  /**
158
   * [watch Causes push notifications to be sent on events which occur in the
159
   * user's mailbox. Requires Google Cloud PubSub.
160
   * see https://developers.google.com/gmail/api/v1/reference/users/watch]
161
   * @param  string $topic             Topic to push events to.
162
   * @param  mixed  $labelIds          Narrow down labels in the mailbox, whose
163
   *                                   mailbox event, are being listened to.
164
   *                                   events are to be listened to.
165
   * @param  string $userId            The ID/Email address of the user.
166
   * @param  string $labelFilterAction [description]
167
   * @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...
168
   */
169
  public function watch(string $topic, $labelIds=null, string $userId='me', string $labelFilterAction='include'):?array {
170
    $body = [
171
      'topicName'         => $topic,
172
      'labelFilterAction' => $labelFilterAction
173
    ];
174
175
    if ($labelIds != null) {
176
      if (is_scalar($labelIds)) {
177
        $body['labelIds'] = [$labelIds];
178
      } elseif (is_array($labelIds)) {
179
        $body['labelIds'] = $labelIds;
180
      }
181
    }
182
183
    list($code, $response) = (new GMailCURL(GMailCURL::POST))(
184
      self::API . "$userId/watch",
185
      ["Authorization: Bearer $this->token"],
186
      $body
187
    );
188
    if ($response !== false) return $this->process_response($code, $response);
189
    return null;
190
  }
191
  /**
192
   * [endWatch stop watch operations on given email ID]
193
   * @date   2019-11-20
194
   * @param  string     $userId ID or Email Address of the user.
195
   * @return bool               [description]
196
   */
197
  public function endWatch(string $userId='me'):bool
198
  {
199
    list($code, $response) = (new GMailCURL(GMailCURL::POST))(
200
      self::API . "$userId/stop",
201
      ["Authorization: Bearer $this->token"]
202
    );
203
    if ($response !== false) return $code == 204;
204
    return false;
205
  }
206
  /**
207
   * [getLabels description]
208
   * @date   2019-11-20
209
   * @param  string     $userID [description]
210
   * @return null|array         [description]
211
   */
212
  public function getLabels(string $userId='me'):?array
213
  {
214
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
215
      self::API . "$userId/labels",
216
      ["Authorization: Bearer $this->token"]
217
    );
218
    if ($response !== false) {
219
      return json_decode($response)->labels;
220
    }
221
    return null;
222
  }
223
  /**
224
   * [getEmails description]
225
   * @date   2019-11-21
226
   * @param  string     $userID           [description]
227
   * @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...
228
   * @param  [type]     $q                [description]
229
   * @param  [type]     $maxEmails        [description]
230
   * @param  [type]     $pageToken        [description]
231
   * @param  boolean    $includeSpamTrash [description]
232
   * @param  [type]     $truncateAfter    [description]
233
   * @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...
234
   */
235
  public function getEmails(string $userId='me', array $labelIds=null,
236
  string $q=null, int $maxEmails=null, string $pageToken=null, bool $includeSpamTrash=false,
237
  $truncateAfter=null):?object
238
  {
239
    $query = [];
240
241
    if ($labelIds != null) $query['labelIds'] = $labelIds;
242
    if ($includeSpamTrash) $query['includeSpamTrash'] = $includeSpamTrash;
243
    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...
244
    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...
245
    if ($maxEmails != null) $query['maxResults'] = $maxEmails;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $maxEmails of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
246
247
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
248
      self::API . "$userId/messages?" . http_build_query($query),
249
      ["Authorization: Bearer $this->token"]
250
    );
251
252
    if ($response !== false) {
253
      if ($truncateAfter != null && $code == 200) {
254
        $response = json_decode($response);
255
        $response->messages = array_filter($response->messages, function ($e) use ($truncateAfter) {
256
          return strcmp($truncateAfter, $e->id) <= 0;
257
        });
258
        $response->{self::HTTP_CODE} = $code;
259
        return $response;
260
      }
261
262
      return $this->process_response($code, $response);
263
    }
264
265
    return null;
266
  }
267
  /**
268
   * [process_response description]
269
   * @param  int    $code   [description]
270
   * @param  string $response [description]
271
   * @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...
272
   */
273
  private function process_response(int $code, string $response) {
274
    $response = json_decode($response);
275
    $response->{self::HTTP_CODE} = $code;
276
    return $response;
277
  }
278
}
279
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
280