friendship ended with social-app. php is my new best friend
1<?php
2/**
3 * Class AccessToken
4 *
5 * @created 09.07.2017
6 * @author Smiley <smiley@chillerlan.net>
7 * @copyright 2017 Smiley
8 * @license MIT
9 *
10 * @filesource
11 */
12declare(strict_types=1);
13
14namespace chillerlan\OAuth\Core;
15
16use chillerlan\Settings\SettingsContainerAbstract;
17use DateInterval, DateTime;
18use function time;
19
20/**
21 * Access token implementation for any OAuth version.
22 *
23 * @link https://datatracker.ietf.org/doc/html/rfc5849#section-2.3
24 * @link https://datatracker.ietf.org/doc/html/rfc6749#section-1.4
25 *
26 * @property string|null $accessToken
27 * @property string|null $accessTokenSecret
28 * @property string|null $refreshToken
29 * @property int $expires
30 * @property string[] $scopes
31 * @property array<string, mixed> $extraParams
32 * @property string|null $provider
33 */
34final class AccessToken extends SettingsContainerAbstract{
35
36 /**
37 * Denotes an unknown end of lifetime, such a token should be considered as expired.
38 *
39 * @var int
40 */
41 public const EXPIRY_UNKNOWN = -0xDEAD;
42
43 /**
44 * Denotes a token which never expires
45 *
46 * @var int
47 */
48 public const NEVER_EXPIRES = -0xCAFE;
49
50 /**
51 * Defines a maximum expiry period (1 year)
52 *
53 * @var int
54 */
55 public const EXPIRY_MAX = (86400 * 365);
56
57 /**
58 * (magic) The oauth access token
59 */
60 protected string|null $accessToken = null;
61
62 /**
63 * (magic) The access token secret (OAuth1)
64 */
65 protected string|null $accessTokenSecret = null;
66
67 /**
68 * (magic) An optional refresh token (OAuth2)
69 */
70 protected string|null $refreshToken = null;
71
72 /**
73 * (magic) The token expiration time
74 *
75 * The getter accepts: `DateTime|DateInterval|int|null`
76 */
77 protected int $expires = self::EXPIRY_UNKNOWN;
78
79 /**
80 * (magic) The scopes that are attached to this token
81 *
82 * @var string[]
83 */
84 protected array $scopes = [];
85
86 /**
87 * (magic) Additional token parameters supplied by the provider
88 *
89 * @var array<string, mixed>
90 */
91 protected array $extraParams = [];
92
93 /**
94 * (magic) The provider that issued the token
95 */
96 protected string|null $provider = null;
97
98 /**
99 * Sets the expiration for this token, clamps the expiry to EXPIRY_MAX
100 *
101 * - `0` sets the expiry to `NEVER_EXPIRES`
102 * - `null`, negative integer values or timestamps from `DateTime` and `DateInterval`
103 * that are in the past set the expiry to `EXPIRY_UNKNOWN`
104 */
105 protected function set_expires(DateTime|DateInterval|int|null $expires = null):void{
106 $now = time();
107 $max = ($now + $this::EXPIRY_MAX);
108
109 $this->expires = match(true){
110 $expires instanceof DateTime => $expires->getTimeStamp(),
111 $expires instanceof DateInterval => (new DateTime)->add($expires)->getTimeStamp(),
112 $expires === 0 || $expires === $this::NEVER_EXPIRES => $this::NEVER_EXPIRES,
113 $expires > $now => $expires,
114 $expires > 0 && $expires <= $this::EXPIRY_MAX => ($now + $expires),
115 default => $this::EXPIRY_UNKNOWN,
116 };
117
118 // clamp possibly expired values
119 if(($expires instanceof DateTime || $expires instanceof DateInterval) && $this->expires < $now){
120 $this->expires = $this::EXPIRY_UNKNOWN;
121 }
122
123 // clamp max expiry
124 if($this->expires > $max){
125 $this->expires = $max; // @codeCoverageIgnore
126 }
127
128 }
129
130 /**
131 * Checks whether this token is expired
132 */
133 public function isExpired():bool{
134
135 if($this->expires === $this::NEVER_EXPIRES){
136 return false;
137 }
138
139 if($this->expires === $this::EXPIRY_UNKNOWN){
140 return true;
141 }
142
143 return time() > $this->expires;
144 }
145
146}