Completed
Branch master (5090d0)
by Pierre-Henry
35:42
created

_protected/app/system/core/classes/UserCore.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @title          User Core Class
4
 *
5
 * @author         Pierre-Henry Soria <[email protected]>
6
 * @copyright      (c) 2012-2018, Pierre-Henry Soria. All Rights Reserved.
7
 * @license        GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory.
8
 * @package        PH7 / App / System / Core / Class
9
 */
10
11
namespace PH7;
12
13
use PH7\Framework\Cache\Cache;
14
use PH7\Framework\Config\Config;
15
use PH7\Framework\File\File;
16
use PH7\Framework\Image\Image;
17
use PH7\Framework\Ip\Ip;
18
use PH7\Framework\Layout\Html\Design;
19
use PH7\Framework\Mvc\Model\DbConfig;
20
use PH7\Framework\Mvc\Model\Engine\Util\Various as VariousModel;
21
use PH7\Framework\Mvc\Model\Security as SecurityModel;
22
use PH7\Framework\Mvc\Request\Http as HttpRequest;
23
use PH7\Framework\Mvc\Router\Uri;
24
use PH7\Framework\Navigation\Browser;
25
use PH7\Framework\Registry\Registry;
26
use PH7\Framework\Security\Validate\Validate;
27
use PH7\Framework\Session\Session;
28
use PH7\Framework\Str\Str;
29
use PH7\Framework\Url\Header;
30
use PH7\Framework\Url\Url;
31
use PH7\Framework\Util\Various;
32
use stdClass;
33
34
// Abstract Class
35
class UserCore
36
{
37
    /**
38
     * Users'levels.
39
     *
40
     * @return bool
41
     */
42
    public static function auth()
43
    {
44
        $oSession = new Session;
45
        $bIsConnected = ((int)$oSession->exists('member_id')) && $oSession->get('member_ip') === Ip::get() && $oSession->get('member_http_user_agent') === (new Browser)->getUserAgent();
46
47
        /** Destroy the object to minimize the CPU resources **/
48
        unset($oSession);
49
50
        return $bIsConnected;
51
    }
52
53
    /**
54
     * Check if an admin is logged as a user.
55
     *
56
     * @return bool
57
     */
58
    public static function isAdminLoggedAs()
59
    {
60
        return (new Session)->exists('login_user_as');
61
    }
62
63
    /**
64
     * Delete User.
65
     *
66
     * @param integer $iProfileId
67
     * @param string $sUsername
68
     *
69
     * @return void
70
     */
71
    public function delete($iProfileId, $sUsername)
72
    {
73
        if ($sUsername == PH7_GHOST_USERNAME) exit('You cannot delete this profile!');
0 ignored issues
show
Coding Style Compatibility introduced by
The method delete() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
74
75
        $oFile = new File;
76
        $oFile->deleteDir(PH7_PATH_PUBLIC_DATA_SYS_MOD . 'user/avatar/' . PH7_IMG . $sUsername);
77
        $oFile->deleteDir(PH7_PATH_PUBLIC_DATA_SYS_MOD . 'user/background/' . PH7_IMG . $sUsername);
78
        $oFile->deleteDir(PH7_PATH_PUBLIC_DATA_SYS_MOD . 'picture/' . PH7_IMG . $sUsername);
79
        $oFile->deleteDir(PH7_PATH_PUBLIC_DATA_SYS_MOD . 'video/file/' . $sUsername);
80
        $oFile->deleteDir(PH7_PATH_PUBLIC_DATA_SYS_MOD . 'note/' . PH7_IMG . $sUsername);
81
        unset($oFile);
82
83
        (new UserCoreModel)->delete($iProfileId, $sUsername);
84
85
        /* Clean UserCoreModel and Avatar Cache */
86
        (new Cache)->start(UserCoreModel::CACHE_GROUP, null, null)->clear()
87
            ->start(Design::CACHE_AVATAR_GROUP . $sUsername, null, null)->clear();
88
    }
89
90
    /**
91
     * Set the avatar file and add it to the database.
92
     *
93
     * @param integer $iProfileId
94
     * @param integer $sUsername
95
     * @param string $sFile
96
     * @param integer $iApproved (1 = approved 0 = pending)
97
     *
98
     * @return bool TRUE if success, FALSE if the extension is wrong.
99
     */
100
    public function setAvatar($iProfileId, $sUsername, $sFile, $iApproved = 1)
101
    {
102
        /**
103
         * This can cause minor errors (eg if a user sent a file that is not a photo).
104
         * So we hide the errors if we are not in development mode.
105
         */
106
        if (!isDebug()) {
107
            error_reporting(0);
108
        }
109
110
        $oAvatar1 = new Image($sFile, 600, 800);
111
112
        if (!$oAvatar1->validate()) {
113
            return false; // File type incompatible!
114
        }
115
116
        // We removes the old avatar if it exists and we delete the cache at the same time.
117
        $this->deleteAvatar($iProfileId, $sUsername);
118
119
        $oAvatar2 = clone $oAvatar1;
120
        $oAvatar3 = clone $oAvatar1;
121
        $oAvatar4 = clone $oAvatar1;
122
        $oAvatar5 = clone $oAvatar1;
123
        $oAvatar6 = clone $oAvatar1;
124
        $oAvatar7 = clone $oAvatar1;
125
        $oAvatar2->square(32);
126
        $oAvatar3->square(64);
127
        $oAvatar4->square(100);
128
        $oAvatar5->square(150);
129
        $oAvatar6->square(200);
130
        $oAvatar7->resize(400);
131
132
        /* Set watermark text on large avatars */
133
        $sWatermarkText = DbConfig::getSetting('watermarkTextImage');
134
        $iSizeWatermarkText = DbConfig::getSetting('sizeWatermarkTextImage');
135
        $oAvatar4->watermarkText($sWatermarkText, $iSizeWatermarkText);
136
        $oAvatar5->watermarkText($sWatermarkText, $iSizeWatermarkText);
137
        $oAvatar6->watermarkText($sWatermarkText, $iSizeWatermarkText);
138
        $oAvatar7->watermarkText($sWatermarkText, $iSizeWatermarkText);
139
140
        $sPath = PH7_PATH_PUBLIC_DATA_SYS_MOD . 'user/avatar/img/' . $sUsername . PH7_SH;
141
        (new File)->createDir($sPath);
142
143
        $sFileName = Various::genRnd($oAvatar1->getFileName(), 1);
144
145
        $sFile1 = $sFileName . '.' . $oAvatar1->getExt();  // Original, four characters
146
        $sFile2 = $sFileName . '-32.' . $oAvatar2->getExt();
147
        $sFile3 = $sFileName . '-64.' . $oAvatar3->getExt();
148
        $sFile4 = $sFileName . '-100.' . $oAvatar4->getExt();
149
        $sFile5 = $sFileName . '-150.' . $oAvatar5->getExt();
150
        $sFile6 = $sFileName . '-200.' . $oAvatar6->getExt();
151
        $sFile7 = $sFileName . '-400.' . $oAvatar7->getExt();
152
153
        // Add the avatar
154
        (new UserCoreModel)->setAvatar($iProfileId, $sFile1, $iApproved);
155
156
        /* Saved the new avatars */
157
        $oAvatar1->save($sPath . $sFile1);
158
        $oAvatar2->save($sPath . $sFile2);
159
        $oAvatar3->save($sPath . $sFile3);
160
        $oAvatar4->save($sPath . $sFile4);
161
        $oAvatar5->save($sPath . $sFile5);
162
        $oAvatar6->save($sPath . $sFile6);
163
        $oAvatar7->save($sPath . $sFile7);
164
165
        unset($oAvatar1, $oAvatar2, $oAvatar3, $oAvatar4, $oAvatar5, $oAvatar6, $oAvatar7);
166
167
        return true;
168
    }
169
170
    /**
171
     * Delete the avatar (image) and track database.
172
     *
173
     * @param integer $iProfileId
174
     * @param string $sUsername
175
     *
176
     * @return void
177
     */
178
    public function deleteAvatar($iProfileId, $sUsername)
179
    {
180
        // We start to delete the file before the data in the database if we could not delete the file since we would have lost the link to the file found in the database.
181
        $sGetAvatar = (new UserCoreModel)->getAvatar($iProfileId, null);
182
        $sFile = $sGetAvatar->pic;
183
184
        $oFile = new File;
185
        $sExt = PH7_DOT . $oFile->getFileExt($sFile);
186
187
        $sPath = PH7_PATH_PUBLIC_DATA_SYS_MOD . 'user/avatar/img/' . $sUsername . PH7_SH;
188
189
        /** Array to the new format (>= PHP5.4) **/
190
        $aFiles = [
191
            $sPath . $sFile,
192
            $sPath . str_replace($sExt, '-32' . $sExt, $sFile),
193
            $sPath . str_replace($sExt, '-64' . $sExt, $sFile),
194
            $sPath . str_replace($sExt, '-100' . $sExt, $sFile),
195
            $sPath . str_replace($sExt, '-150' . $sExt, $sFile),
196
            $sPath . str_replace($sExt, '-200' . $sExt, $sFile),
197
            $sPath . str_replace($sExt, '-400' . $sExt, $sFile),
198
        ];
199
200
        $oFile->deleteFile($aFiles);
201
        unset($oFile);
202
203
        (new UserCoreModel)->deleteAvatar($iProfileId);
204
205
        /* Clean User Avatar Cache */
206
        (new Cache)->start(Design::CACHE_AVATAR_GROUP . $sUsername, null, null)->clear()
207
            ->start(UserCoreModel::CACHE_GROUP, 'avatar' . $iProfileId, null)->clear();
208
    }
209
210
    /**
211
     * Set a background on user profile.
212
     *
213
     * @param integer $iProfileId
214
     * @param string $sUsername
215
     * @param string $sFile
216
     * @param integer $iApproved (1 = approved 0 = pending)
217
     *
218
     * @return bool TRUE if success, FALSE if the extension is wrong.
219
     */
220
    public function setBackground($iProfileId, $sUsername, $sFile, $iApproved = 1)
221
    {
222
        /**
223
         * This can cause minor errors (eg if a user sent a file that is not a photo).
224
         * So we hide the errors if we are not in development mode.
225
         */
226
        if (!isDebug()) {
227
            error_reporting(0);
228
        }
229
230
        $oWallpaper = new Image($sFile, 600, 800);
231
232
        if (!$oWallpaper->validate()) {
233
            return false;
234
        }
235
236
        // We removes the old background if it exists and we delete the cache at the same time.
237
        $this->deleteBackground($iProfileId, $sUsername);
238
239
240
        $sPath = PH7_PATH_PUBLIC_DATA_SYS_MOD . 'user/background/img/' . $sUsername . PH7_SH;
241
        (new File)->createDir($sPath);
242
243
        $sFileName = Various::genRnd($oWallpaper->getFileName(), 1);
244
        $sFile = $sFileName . '.' . $oWallpaper->getExt();
245
246
        // Add the profile background
247
        (new UserCoreModel)->addBackground($iProfileId, $sFile, $iApproved);
248
249
        // Saved the new background
250
        $oWallpaper->save($sPath . $sFile);
251
252
        unset($oWallpaper);
253
254
        return true;
255
    }
256
257
    /**
258
     * @param integer $iProfileId
259
     * @param string $sUsername
260
     *
261
     * @return void
262
     */
263
    public function deleteBackground($iProfileId, $sUsername)
264
    {
265
        // We start to delete the file before the data in the database if we could not delete the file since we would have lost the link to the file found in the database.
266
        $sFile = (new UserCoreModel)->getBackground($iProfileId, null);
267
268
        (new File)->deleteFile(PH7_PATH_PUBLIC_DATA_SYS_MOD . 'user/background/img/' . $sUsername . PH7_SH . $sFile);
269
        (new UserCoreModel)->deleteBackground($iProfileId);
270
271
        /* Clean User Background Cache */
272
        (new Cache)->start(UserCoreModel::CACHE_GROUP, 'background' . $iProfileId, null)->clear();
273
    }
274
275
    /**
276
     * Get the Profile Link.
277
     *
278
     * @param string $sUsername
279
     *
280
     * @return string The Absolute Profile Link
281
     */
282
    public function getProfileLink($sUsername)
283
    {
284
        $sUsername = (new Str)->lower($sUsername);
285
        //return (strlen($sUsername) >1) ? PH7_URL_ROOT . $sUsername . PH7_PAGE_EXT : '#';
286
287
        return PH7_URL_ROOT . $sUsername . PH7_PAGE_EXT;
288
    }
289
290
    /**
291
     * Get Profile Link with the link to the registration form if the user is not connected.
292
     *
293
     * @param string $sUsername
294
     * @param string $sFirstName
295
     * @param string $sSex
296
     *
297
     * @return string The link
298
     */
299
    public function getProfileSignupLink($sUsername, $sFirstName, $sSex)
300
    {
301
        if (!self::auth() && !AdminCore::auth()) {
302
            $aHttpParams = [
303
                'ref' => (new HttpRequest)->currentController(),
304
                'a' => Registry::getInstance()->action,
305
                'u' => $sUsername,
306
                'f_n' => $sFirstName,
307
                's' => $sSex
308
            ];
309
310
            $sLink = Uri::get('user', 'signup', 'step1', '?' . Url::httpBuildQuery($aHttpParams), false);
311
        } else {
312
            $sLink = $this->getProfileLink($sUsername);
313
        }
314
315
        return $sLink;
316
    }
317
318
    /**
319
     * Set a user authentication.
320
     *
321
     * @param stdClass $oUserData User database object.
322
     * @param UserCoreModel $oUserModel
323
     * @param Session $oSession
324
     * @param SecurityModel $oSecurityModel
325
     *
326
     * @return void
327
     */
328
    public function setAuth(stdClass $oUserData, UserCoreModel $oUserModel, Session $oSession, SecurityModel $oSecurityModel)
329
    {
330
        // Remove the session if the user is logged on as "affiliate" or "administrator".
331
        if (AffiliateCore::auth() || AdminCore::auth()) {
332
            $oSession->destroy();
333
        }
334
335
        // Regenerate the session ID to prevent session fixation attack
336
        $oSession->regenerateId();
337
338
        // Now we connect the member
339
        $aSessionData = [
340
            'member_id' => $oUserData->profileId,
341
            'member_email' => $oUserData->email,
342
            'member_username' => $oUserData->username,
343
            'member_first_name' => $oUserData->firstName,
344
            'member_sex' => $oUserData->sex,
345
            'member_group_id' => $oUserData->groupId,
346
            'member_ip' => Ip::get(),
347
            'member_http_user_agent' => (new Browser)->getUserAgent(),
348
            'member_token' => Various::genRnd($oUserData->email)
349
        ];
350
351
        $oSession->set($aSessionData);
352
353
        $oSecurityModel->addLoginLog($oUserData->email, $oUserData->username, '*****', 'Logged in!');
354
        $oUserModel->setLastActivity($oUserData->profileId);
355
    }
356
357
    /**
358
     * Finds a free username in our database to use for Facebook connect.
359
     *
360
     * @param string $sNickname
361
     * @param string $sFirstName
362
     * @param string $sLastName
363
     *
364
     * @return string Username
365
     */
366
    public function findUsername($sNickname, $sFirstName, $sLastName)
367
    {
368
        $iMaxLen = DbConfig::getSetting('maxUsernameLength');
369
        $sRnd = Various::genRnd('pH_Pierre-Henry_Soria_Sanz_González', 4); // Random String
370
371
        $aUsernameList = [
372
            $sNickname,
373
            $sFirstName,
374
            $sLastName,
375
            $sNickname . $sRnd,
376
            $sFirstName . $sRnd,
377
            $sLastName . $sRnd,
378
            $sFirstName . '-' . $sLastName,
379
            $sLastName . '-' . $sFirstName,
380
            $sFirstName . '-' . $sLastName . $sRnd,
381
            $sLastName . '-' . $sFirstName . $sRnd
382
        ];
383
384
        foreach ($aUsernameList as $sUsername) {
385
            $sUsername = substr($sUsername, 0, $iMaxLen);
386
387
            if ((new Validate)->username($sUsername))
388
                break;
389
            else
390
                $sUsername = Various::genRnd('pOH_Pierre-Henry_Soria_Béghin_Rollier', $iMaxLen); // Default value
391
        }
392
393
        return $sUsername;
394
    }
395
396
    /**
397
     * Check account status of profile.
398
     *
399
     * @param stdClass $oDbProfileData User database object.
400
     *
401
     * @return bool|string Returns a boolean TRUE if the account status is correct, otherwise returns an error message.
402
     */
403
    public function checkAccountStatus(stdClass $oDbProfileData)
404
    {
405
        $mRet = true; // Default value
406
407
        if ($oDbProfileData->active != 1) {
408
            if ($oDbProfileData->active == 2) {
409
                $mRet = t('Sorry, your account has not been activated yet. Please activate it by clicking the activation link that was emailed.');
410
            } elseif ($oDbProfileData->active == 3) {
411
                $mRet = t('Sorry, your account has not been activated yet. An administrator must validate your account.');
412
            } else {
413
                $mRet = t('Your account does not have a valid activation status. Please contact the database administrator so that it solves this problem.');
414
            }
415
        } elseif ($oDbProfileData->ban == 1) {
416
            $mRet = t('Sorry, Your account has been banned.');
417
        }
418
419
        return $mRet;
420
    }
421
422
    /**
423
     * Message and Redirection for Activate Account.
424
     *
425
     * @param string $sEmail
426
     * @param string $sHash
427
     * @param Config $oConfig
428
     * @param Registry $oRegistry
429
     * @param string $sMod (user, affiliate, newsletter).
430
     *
431
     * @return void
432
     */
433
    public function activateAccount($sEmail, $sHash, Config $oConfig, Registry $oRegistry, $sMod = 'user')
434
    {
435
        $sTable = VariousModel::convertModToTable($sMod);
436
        $sRedirectLoginUrl = ($sMod == 'newsletter' ? PH7_URL_ROOT : ($sMod == 'affiliate' ? Uri::get('affiliate', 'home', 'login') : Uri::get('user', 'main', 'login')));
437
        $sRedirectIndexUrl = ($sMod == 'newsletter' ? PH7_URL_ROOT : ($sMod == 'affiliate' ? Uri::get('affiliate', 'home', 'index') : Uri::get('user', 'main', 'index')));
438
        $sSuccessMsg = ($sMod == 'newsletter' ? t('Your subscription to our newsletters has been successfully validated!') : t('Your account has been successfully validated. You can now login!'));
439
440
        if (isset($sEmail, $sHash)) {
441
            $oUserModel = new AffiliateCoreModel;
442
            if ($oUserModel->validateAccount($sEmail, $sHash, $sTable)) {
443
                $iId = $oUserModel->getId($sEmail, null, $sTable);
444
                if ($sMod != 'newsletter') {
445
                    $this->clearReadProfileCache($iId, $sTable);
446
                }
447
448
                /** Update the Affiliate Commission **/
449
                $iAffId = $oUserModel->getAffiliatedId($iId);
450
                AffiliateCore::updateJoinCom($iAffId, $oConfig, $oRegistry);
451
452
                Header::redirect($sRedirectLoginUrl, $sSuccessMsg);
453
            } else {
454
                Header::redirect($sRedirectLoginUrl, t('Oops! The URL is either invalid or you already have activated your account.'), 'error');
455
            }
456
            unset($oUserModel);
457
        } else {
458
            Header::redirect($sRedirectIndexUrl, t('Invalid approach, please use the link that has been send to your email.'), 'error');
459
        }
460
    }
461
462
    /**
463
     * Get the correct matching sex.
464
     *
465
     * @param string $sSex
466
     *
467
     * @return string The Match Sex.
468
     */
469
    public function getMatchSex($sSex)
470
    {
471
        return ($sSex == 'male' ? 'female' : ($sSex == 'female' ? 'male' : 'couple'));
472
    }
473
474
    /**
475
     * This method is a wrapper for the cache of the profile of users.
476
     * Clean UserCoreModel / readProfile Cache
477
     *
478
     * @param integer $iId Profile ID.
479
     * @param string $sTable Default 'Members'
480
     *
481
     * @return void
482
     */
483
    public function clearReadProfileCache($iId, $sTable = 'Members')
484
    {
485
        $this->clearCache('readProfile', $iId, $sTable);
486
    }
487
488
    /**
489
     * This method is a wrapper for the Info Fields cache.
490
     * Clean UserCoreModel / infoFields Cache
491
     *
492
     * @param integer $iId Profile ID.
493
     * @param string $sTable Default 'MembersInfo'
494
     *
495
     * @return void
496
     */
497
    public function clearInfoFieldCache($iId, $sTable = 'MembersInfo')
498
    {
499
        $this->clearCache('infoFields', $iId, $sTable);
500
    }
501
502
    /**
503
     * Generic method to clear the user cache.
504
     *
505
     * @param string $sId Cache ID.
506
     * @param integer $iId User ID.
507
     * @param string $sTable Table name.
508
     *
509
     * @return void
510
     */
511
    private function clearCache($sId, $iId, $sTable)
512
    {
513
        VariousModel::checkModelTable($sTable);
514
515
        (new Cache)->start(UserCoreModel::CACHE_GROUP, $sId . $iId . $sTable, null)->clear();
516
    }
517
518
    /**
519
     * Clone is set to private to stop cloning.
520
     */
521
    private function __clone()
522
    {
523
    }
524
}
525