1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Apps\Model\Front\User; |
4
|
|
|
|
5
|
|
|
use Apps\ActiveRecord\UserProvider; |
6
|
|
|
use Apps\Model\Front\Profile\FormAvatarUpload; |
7
|
|
|
use Ffcms\Core\App; |
8
|
|
|
use Ffcms\Core\Arch\Model; |
9
|
|
|
use Ffcms\Core\Exception\ForbiddenException; |
10
|
|
|
use Ffcms\Core\Helper\FileSystem\File; |
11
|
|
|
use Ffcms\Core\Helper\Type\Arr; |
12
|
|
|
use Ffcms\Core\Helper\Type\Str; |
13
|
|
|
use Ffcms\Core\Helper\Url; |
14
|
|
|
use Ffcms\Core\Interfaces\iUser; |
15
|
|
|
use \Symfony\Component\HttpFoundation\File\File as FileObject; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class FormSocialAuth. Model of social authorization and registering on top layer of register model. |
19
|
|
|
* @package Apps\Model\Front\User |
20
|
|
|
*/ |
21
|
|
|
class FormSocialAuth extends FormRegister |
22
|
|
|
{ |
23
|
|
|
/** @var string */ |
24
|
|
|
public $profileLink; |
25
|
|
|
|
26
|
|
|
/** @var string */ |
27
|
|
|
private $_provider_name; |
28
|
|
|
private $_provider_id; |
29
|
|
|
/** @var \Hybrid_User_Profile */ |
30
|
|
|
private $_identity; |
31
|
|
|
/** @var UserProvider */ |
32
|
|
|
private $_record; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* FormSocialAuth constructor. Pass provider name as string and identity as object of hybrid auth |
36
|
|
|
* @param bool $provider |
37
|
|
|
* @param $identity |
38
|
|
|
*/ |
39
|
|
|
public function __construct($provider, $identity) |
40
|
|
|
{ |
41
|
|
|
$this->_provider_name = (string)$provider; |
42
|
|
|
$this->_identity = $identity; |
43
|
|
|
parent::__construct(false); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Parse user identifier to attributes |
48
|
|
|
*/ |
49
|
|
|
public function before() |
50
|
|
|
{ |
51
|
|
|
// set unique user id from provider response |
52
|
|
|
$this->_provider_id = $this->_identity->identifier; |
53
|
|
|
|
54
|
|
|
// grab some data from identity provider |
55
|
|
|
if ($this->email === null) { |
56
|
|
|
$this->email = $this->_identity->email; |
57
|
|
|
} |
58
|
|
|
$this->profileLink = $this->_identity->profileURL; |
59
|
|
|
|
60
|
|
|
// get record info from db for this identifier if exists |
61
|
|
|
$this->_record = UserProvider::where('provider_name', '=', $this->_provider_name) |
|
|
|
|
62
|
|
|
->where('provider_id', '=', $this->_provider_id) |
63
|
|
|
->first(); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Check if this identity always exists |
68
|
|
|
* @return bool |
69
|
|
|
*/ |
70
|
|
|
public function identityExists() |
71
|
|
|
{ |
72
|
|
|
return ($this->_record !== null && $this->_record->count() === 1); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Make user authorization from social identity to website session |
77
|
|
|
* @return bool |
78
|
|
|
* @throws \Ffcms\Core\Exception\ForbiddenException |
79
|
|
|
*/ |
80
|
|
|
public function makeAuth() |
81
|
|
|
{ |
82
|
|
|
if ($this->_record === null) { |
83
|
|
|
return false; |
84
|
|
|
} |
85
|
|
|
// get user from belongsTo relation |
86
|
|
|
$user = $this->_record->user; |
|
|
|
|
87
|
|
|
// maybe user was deleted without data provider record? |
88
|
|
|
if (!$user instanceof iUser) { |
89
|
|
|
throw new ForbiddenException(__('User related to this social account was deleted')); |
90
|
|
|
} |
91
|
|
|
// initialize login model |
92
|
|
|
$loginModel = new FormLogin(); |
93
|
|
|
// open session & return status |
94
|
|
|
return $loginModel->openSession($user); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Override default registration function with social auth data compatability |
99
|
|
|
* @param bool $activation |
100
|
|
|
* @return bool |
101
|
|
|
*/ |
102
|
|
|
public function tryRegister($activation = false) |
103
|
|
|
{ |
104
|
|
|
// try to complete register process |
105
|
|
|
$success = parent::tryRegister($activation); |
106
|
|
|
if ($success && $this->_userObject !== null) { |
107
|
|
|
// save remote auth data to relation table |
108
|
|
|
$provider = new UserProvider(); |
109
|
|
|
$provider->provider_name = $this->_provider_name; |
110
|
|
|
$provider->provider_id = $this->_provider_id; |
111
|
|
|
$provider->user_id = $this->_userObject->id; |
112
|
|
|
$provider->save(); |
113
|
|
|
|
114
|
|
|
// get profile object from attr |
115
|
|
|
$profile = $this->_profileObject; |
116
|
|
|
// set nickname from remote service |
117
|
|
|
if (!Str::likeEmpty($this->_identity->displayName)) { |
118
|
|
|
$profile->nick = $this->_identity->displayName; |
119
|
|
|
} |
120
|
|
|
// set profile as user website |
121
|
|
|
$profile->url = $this->_identity->profileURL; |
122
|
|
|
// try to get gender (sex) |
123
|
|
|
if ($this->_identity->gender !== null) { |
124
|
|
|
$profile->sex = $this->_identity->gender === 'female' ? 2 : 1; |
125
|
|
|
} |
126
|
|
|
// set birthday if available |
127
|
|
|
if ($this->_identity->birthDay !== null && $this->_identity->birthMonth !== null && $this->_identity->birthYear !== null) { |
128
|
|
|
$profile->birthday = $this->_identity->birthYear . '-' . $this->_identity->birthMonth . '-' . $this->_identity->birthDay; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
// try to parse avatar from remote service |
132
|
|
|
if ($this->_identity->photoURL !== null) { |
133
|
|
|
$this->parseAvatar($this->_identity->photoURL, $this->_userObject->id); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
// save profile data |
137
|
|
|
$profile->save(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $success; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Try to download and parse remote avatar |
145
|
|
|
* @param string $url |
146
|
|
|
* @param int $userId |
147
|
|
|
*/ |
148
|
|
|
protected function parseAvatar($url, $userId) |
149
|
|
|
{ |
150
|
|
|
// check if user is defined |
151
|
|
|
if ((int)$userId < 1) { |
152
|
|
|
return; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
// check remote image extension |
156
|
|
|
$imageExtension = Str::lastIn($url, '.', true); |
157
|
|
|
if (!Arr::in($imageExtension, ['png', 'gif', 'jpg', 'jpeg'])) { |
|
|
|
|
158
|
|
|
return; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
// try to get image binary data |
162
|
|
|
$imageContent = Url::download($url); |
|
|
|
|
163
|
|
|
if ($imageContent === null || Str::likeEmpty($imageContent)) { |
164
|
|
|
return; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
// write image to filesystem |
168
|
|
|
$imagePath = '/upload/user/avatar/original/' . $userId . '.' . $imageExtension; |
169
|
|
|
$write = File::write($imagePath, $imageContent); |
170
|
|
|
if ($write === false) { |
171
|
|
|
return; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
// try to write and resize file |
175
|
|
|
try { |
176
|
|
|
$fileObject = new FileObject(root . $imagePath); |
177
|
|
|
$avatarUpload = new FormAvatarUpload(); |
178
|
|
|
$avatarUpload->resizeAndSave($fileObject, $userId, 'small'); |
179
|
|
|
$avatarUpload->resizeAndSave($fileObject, $userId, 'medium'); |
180
|
|
|
$avatarUpload->resizeAndSave($fileObject, $userId, 'big'); |
181
|
|
|
} catch (\Exception $e) { |
182
|
|
|
if (App::$Debug) { |
183
|
|
|
App::$Debug->addException($e); |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
} |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.