Passed
Push — 1.11.x ( 20be1d...6563e4 )
by Julito
10:41
created

UserManager::checkEmail()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
6
use Chamilo\CoreBundle\Entity\Repository\AccessUrlRepository;
7
use Chamilo\CoreBundle\Entity\SkillRelUser;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, SkillRelUser. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use Chamilo\CoreBundle\Entity\SkillRelUserComment;
9
use Chamilo\UserBundle\Entity\User;
10
use Chamilo\UserBundle\Repository\UserRepository;
11
use ChamiloSession as Session;
12
use Symfony\Component\Filesystem\Filesystem;
13
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
14
15
/**
16
 * Class UserManager.
17
 *
18
 * This library provides functions for user management.
19
 * Include/require it in your code to use its functionality.
20
 *
21
 * @author Julio Montoya <[email protected]> Social network groups added 2009/12
22
 */
23
class UserManager
24
{
25
    // This constants are deprecated use the constants located in ExtraField
26
    const USER_FIELD_TYPE_TEXT = 1;
27
    const USER_FIELD_TYPE_TEXTAREA = 2;
28
    const USER_FIELD_TYPE_RADIO = 3;
29
    const USER_FIELD_TYPE_SELECT = 4;
30
    const USER_FIELD_TYPE_SELECT_MULTIPLE = 5;
31
    const USER_FIELD_TYPE_DATE = 6;
32
    const USER_FIELD_TYPE_DATETIME = 7;
33
    const USER_FIELD_TYPE_DOUBLE_SELECT = 8;
34
    const USER_FIELD_TYPE_DIVIDER = 9;
35
    const USER_FIELD_TYPE_TAG = 10;
36
    const USER_FIELD_TYPE_TIMEZONE = 11;
37
    const USER_FIELD_TYPE_SOCIAL_PROFILE = 12;
38
    const USER_FIELD_TYPE_FILE = 13;
39
    const USER_FIELD_TYPE_MOBILE_PHONE_NUMBER = 14;
40
41
    private static $encryptionMethod;
42
43
    /**
44
     * Constructor.
45
     *
46
     * @assert () === null
47
     */
48
    public function __construct()
49
    {
50
    }
51
52
    /**
53
     * Repository is use to query the DB, selects, etc.
54
     *
55
     * @return UserRepository
56
     */
57
    public static function getRepository()
58
    {
59
        /** @var UserRepository $userRepository */
60
61
        return Database::getManager()->getRepository('ChamiloUserBundle:User');
62
    }
63
64
    /**
65
     * Create/update/delete methods are available in the UserManager
66
     * (based in the Sonata\UserBundle\Entity\UserManager).
67
     *
68
     * @return Chamilo\UserBundle\Entity\Manager\UserManager
69
     */
70
    public static function getManager()
71
    {
72
        static $userManager;
73
74
        if (!isset($userManager)) {
75
            $encoderFactory = self::getEncoderFactory();
76
            $userManager = new Chamilo\UserBundle\Entity\Manager\UserManager(
77
                $encoderFactory,
78
                new \FOS\UserBundle\Util\Canonicalizer(),
79
                new \FOS\UserBundle\Util\Canonicalizer(),
80
                Database::getManager(),
81
                'Chamilo\\UserBundle\\Entity\\User'
82
            );
83
        }
84
85
        return $userManager;
86
    }
87
88
    /**
89
     * @param string $encryptionMethod
90
     */
91
    public static function setPasswordEncryption($encryptionMethod)
92
    {
93
        self::$encryptionMethod = $encryptionMethod;
94
    }
95
96
    /**
97
     * @return bool|mixed
98
     */
99
    public static function getPasswordEncryption()
100
    {
101
        $encryptionMethod = self::$encryptionMethod;
102
        if (empty($encryptionMethod)) {
103
            $encryptionMethod = api_get_configuration_value('password_encryption');
104
        }
105
106
        return $encryptionMethod;
107
    }
108
109
    /**
110
     * Validates the password.
111
     *
112
     * @param $encoded
113
     * @param $raw
114
     * @param $salt
115
     *
116
     * @return bool
117
     */
118
    public static function isPasswordValid($encoded, $raw, $salt)
119
    {
120
        $encoder = new \Chamilo\UserBundle\Security\Encoder(self::getPasswordEncryption());
121
122
        return $encoder->isPasswordValid($encoded, $raw, $salt);
123
    }
124
125
    /**
126
     * @param string $raw
127
     *
128
     * @return string
129
     */
130
    public static function encryptPassword($raw, User $user)
131
    {
132
        $encoder = self::getEncoder($user);
133
134
        return $encoder->encodePassword(
135
            $raw,
136
            $user->getSalt()
137
        );
138
    }
139
140
    /**
141
     * @param int    $userId
142
     * @param string $password
143
     */
144
    public static function updatePassword($userId, $password)
145
    {
146
        $repository = self::getRepository();
147
        /** @var User $user */
148
        $user = $repository->find($userId);
149
        $userManager = self::getManager();
150
        $user->setPlainPassword($password);
151
        $userManager->updateUser($user, true);
152
        Event::addEvent(LOG_USER_PASSWORD_UPDATE, LOG_USER_ID, $userId);
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

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

152
        Event::/** @scrutinizer ignore-call */ 
153
               addEvent(LOG_USER_PASSWORD_UPDATE, LOG_USER_ID, $userId);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
153
    }
154
155
    /**
156
     * Creates a new user for the platform.
157
     *
158
     * @author Hugues Peeters <[email protected]>,
159
     * @author Roan Embrechts <[email protected]>
160
     *
161
     * @param string        $firstName
162
     * @param string        $lastName
163
     * @param int           $status                  (1 for course tutor, 5 for student, 6 for anonymous)
164
     * @param string        $email
165
     * @param string        $loginName
166
     * @param string        $password
167
     * @param string        $official_code           Any official code (optional)
168
     * @param string        $language                User language    (optional)
169
     * @param string        $phone                   Phone number    (optional)
170
     * @param string        $picture_uri             Picture URI        (optional)
171
     * @param string        $authSource              Authentication source (defaults to 'platform', dependind on constant)
172
     * @param string        $expirationDate          Account expiration date (optional, defaults to null)
173
     * @param int           $active                  Whether the account is enabled or disabled by default
174
     * @param int           $hr_dept_id              The department of HR in which the user is registered (defaults to 0)
175
     * @param array         $extra                   Extra fields
176
     * @param string        $encrypt_method          Used if password is given encrypted. Set to an empty string by default
177
     * @param bool          $send_mail
178
     * @param bool          $isAdmin
179
     * @param string        $address
180
     * @param bool          $sendEmailToAllAdmins
181
     * @param FormValidator $form
182
     * @param int           $creatorId
183
     * @param array         $emailTemplate
184
     * @param string        $redirectToURLAfterLogin
185
     *
186
     * @return mixed new user id - if the new user creation succeeds, false otherwise
187
     * @desc The function tries to retrieve user id from the session.
188
     * If it exists, the current user id is the creator id. If a problem arises,
189
     * @assert ('Sam','Gamegie',5,'[email protected]','jo','jo') > 1
190
     * @assert ('Pippin','Took',null,null,'jo','jo') === false
191
     */
192
    public static function create_user(
193
        $firstName,
194
        $lastName,
195
        $status,
196
        $email,
197
        $loginName,
198
        $password,
199
        $official_code = '',
200
        $language = '',
201
        $phone = '',
202
        $picture_uri = '',
203
        $authSource = PLATFORM_AUTH_SOURCE,
204
        $expirationDate = null,
205
        $active = 1,
206
        $hr_dept_id = 0,
207
        $extra = [],
208
        $encrypt_method = '',
209
        $send_mail = false,
210
        $isAdmin = false,
211
        $address = '',
212
        $sendEmailToAllAdmins = false,
213
        $form = null,
214
        $creatorId = 0,
215
        $emailTemplate = [],
216
        $redirectToURLAfterLogin = ''
217
    ) {
218
        $creatorId = empty($creatorId) ? api_get_user_id() : 0;
219
        $creatorInfo = api_get_user_info($creatorId);
220
        $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
221
222
        $hook = HookCreateUser::create();
223
        if (!empty($hook)) {
224
            $hook->notifyCreateUser(HOOK_EVENT_TYPE_PRE);
225
        }
226
227
        if ('true' === api_get_setting('registration', 'email')) {
228
            // Force email validation.
229
           if (false === api_valid_email($email)) {
230
               Display::addFlash(
231
                   Display::return_message(get_lang('PleaseEnterValidEmail').' - '.$email, 'warning')
232
               );
233
234
               return false;
235
           }
236
        } else {
237
            // Allow empty email. If email is set, check if is valid.
238
            if (!empty($email) && false === api_valid_email($email)) {
239
                Display::addFlash(
240
                    Display::return_message(get_lang('PleaseEnterValidEmail').' - '.$email, 'warning')
241
                );
242
243
                return false;
244
            }
245
        }
246
247
        if ('true' === api_get_setting('login_is_email')) {
248
            if (false === api_valid_email($loginName)) {
249
                Display::addFlash(
250
                    Display::return_message(get_lang('PleaseEnterValidEmail').' - '.$loginName, 'warning')
251
                );
252
253
                return false;
254
            }
255
        } else {
256
            if (false === self::is_username_valid($loginName)) {
257
                Display::addFlash(
258
                    Display::return_message(get_lang('UsernameWrong').' - '.$loginName, 'warning')
259
                );
260
261
                return false;
262
            }
263
        }
264
265
        // First check wether the login already exists
266
        if (!self::is_username_available($loginName)) {
267
            Display::addFlash(
268
                Display::return_message(get_lang('LoginAlreadyTaken').' - '.$loginName, 'warning')
269
            );
270
271
            return false;
272
        }
273
274
        global $_configuration;
275
        $original_password = $password;
276
277
        $access_url_id = 1;
278
        if (api_get_multiple_access_url()) {
279
            $access_url_id = api_get_current_access_url_id();
280
        } else {
281
            // In some cases, the first access_url ID might be different from 1
282
            // for example when using a DB cluster or hacking the DB manually.
283
            // In this case, we want the first row, not necessarily "1".
284
            $dbm = Database::getManager();
285
            /** @var AccessUrlRepository $accessUrlRepository */
286
            $accessUrlRepository = $dbm->getRepository('ChamiloCoreBundle:AccessUrl');
287
            $accessUrl = $accessUrlRepository->getFirstId();
288
            if (!empty($accessUrl[0]) && !empty($accessUrl[0][1])) {
289
                $access_url_id = $accessUrl[0][1];
290
            }
291
        }
292
293
        if (isset($_configuration[$access_url_id]) &&
294
            is_array($_configuration[$access_url_id]) &&
295
            isset($_configuration[$access_url_id]['hosting_limit_users']) &&
296
            $_configuration[$access_url_id]['hosting_limit_users'] > 0) {
297
            $num = self::get_number_of_users(null, $access_url_id);
298
            if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
299
                api_warn_hosting_contact('hosting_limit_users');
300
                Display::addFlash(
301
                    Display::return_message(
302
                        get_lang('PortalUsersLimitReached'),
303
                        'warning'
304
                    )
305
                );
306
307
                return false;
308
            }
309
        }
310
311
        if ($status === 1 &&
312
            isset($_configuration[$access_url_id]) &&
313
            is_array($_configuration[$access_url_id]) &&
314
            isset($_configuration[$access_url_id]['hosting_limit_teachers']) &&
315
            $_configuration[$access_url_id]['hosting_limit_teachers'] > 0
316
        ) {
317
            $num = self::get_number_of_users(1, $access_url_id);
318
            if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
319
                Display::addFlash(
320
                    Display::return_message(
321
                        get_lang('PortalTeachersLimitReached'),
322
                        'warning'
323
                    )
324
                );
325
                api_warn_hosting_contact('hosting_limit_teachers');
326
327
                return false;
328
            }
329
        }
330
331
        if (empty($password)) {
332
            if ($authSource === PLATFORM_AUTH_SOURCE) {
333
                Display::addFlash(
334
                    Display::return_message(
335
                        get_lang('ThisFieldIsRequired').': '.get_lang(
336
                            'Password'
337
                        ),
338
                        'warning'
339
                    )
340
                );
341
342
                return false;
343
            }
344
345
            // We use the authSource as password.
346
            // The real validation will be by processed by the auth
347
            // source not Chamilo
348
            $password = $authSource;
349
        }
350
351
        // database table definition
352
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
353
354
        // Checking the user language
355
        $languages = api_get_languages();
356
        $language = strtolower($language);
357
358
        if (isset($languages['folder'])) {
359
            if (!in_array($language, $languages['folder'])) {
360
                $language = api_get_setting('platformLanguage');
361
            }
362
        }
363
364
        $currentDate = api_get_utc_datetime();
365
        $now = new DateTime();
366
367
        if (empty($expirationDate) || $expirationDate == '0000-00-00 00:00:00') {
368
            // Default expiration date
369
            // if there is a default duration of a valid account then
370
            // we have to change the expiration_date accordingly
371
            // Accept 0000-00-00 00:00:00 as a null value to avoid issues with
372
            // third party code using this method with the previous (pre-1.10)
373
            // value of 0000...
374
            if (api_get_setting('account_valid_duration') != '') {
375
                $expirationDate = new DateTime($currentDate);
376
                $days = (int) api_get_setting('account_valid_duration');
377
                $expirationDate->modify('+'.$days.' day');
378
            }
379
        } else {
380
            $expirationDate = api_get_utc_datetime($expirationDate);
381
            $expirationDate = new \DateTime($expirationDate, new DateTimeZone('UTC'));
382
        }
383
384
        $userManager = self::getManager();
385
386
        /** @var User $user */
387
        $user = $userManager->createUser();
388
389
        $user
390
            ->setLastname($lastName)
391
            ->setFirstname($firstName)
392
            ->setUsername($loginName)
393
            ->setStatus($status)
394
            ->setPlainPassword($password)
395
            ->setEmail($email)
396
            ->setOfficialCode($official_code)
397
            ->setPictureUri($picture_uri)
398
            ->setCreatorId($creatorId)
399
            ->setAuthSource($authSource)
400
            ->setPhone($phone)
401
            ->setAddress($address)
402
            ->setLanguage($language)
403
            ->setRegistrationDate($now)
404
            ->setHrDeptId($hr_dept_id)
405
            ->setActive($active)
406
            ->setEnabled($active)
407
        ;
408
409
        if (!empty($expirationDate)) {
410
            $user->setExpirationDate($expirationDate);
411
        }
412
413
        $userManager->updateUser($user);
414
        $userId = $user->getId();
415
416
        if (!empty($userId)) {
417
            $return = $userId;
418
            $sql = "UPDATE $table_user SET user_id = $return WHERE id = $return";
419
            Database::query($sql);
420
421
            if ($isAdmin) {
422
                self::addUserAsAdmin($user);
423
            }
424
425
            if (api_get_multiple_access_url()) {
426
                UrlManager::add_user_to_url($userId, api_get_current_access_url_id());
427
            } else {
428
                //we are adding by default the access_url_user table with access_url_id = 1
429
                UrlManager::add_user_to_url($userId, 1);
430
            }
431
432
            $extra['item_id'] = $userId;
433
434
            if (is_array($extra) && count($extra) > 0) {
435
                $courseFieldValue = new ExtraFieldValue('user');
436
                $courseFieldValue->saveFieldValues($extra);
437
            } else {
438
                // Create notify settings by default
439
                self::update_extra_field_value(
440
                    $userId,
441
                    'mail_notify_invitation',
442
                    '1'
443
                );
444
                self::update_extra_field_value(
445
                    $userId,
446
                    'mail_notify_message',
447
                    '1'
448
                );
449
                self::update_extra_field_value(
450
                    $userId,
451
                    'mail_notify_group_message',
452
                    '1'
453
                );
454
            }
455
456
            self::update_extra_field_value(
457
                $userId,
458
                'already_logged_in',
459
                'false'
460
            );
461
462
            if (!empty($redirectToURLAfterLogin) && api_get_configuration_value('plugin_redirection_enabled')) {
463
                RedirectionPlugin::insert($userId, $redirectToURLAfterLogin);
464
            }
465
466
            if (!empty($email) && $send_mail) {
467
                $recipient_name = api_get_person_name(
468
                    $firstName,
469
                    $lastName,
470
                    null,
471
                    PERSON_NAME_EMAIL_ADDRESS
472
                );
473
                $tplSubject = new Template(
474
                    null,
475
                    false,
476
                    false,
477
                    false,
478
                    false,
479
                    false
480
                );
481
                $layoutSubject = $tplSubject->get_template('mail/subject_registration_platform.tpl');
482
                $emailSubject = $tplSubject->fetch($layoutSubject);
483
                $sender_name = api_get_person_name(
484
                    api_get_setting('administratorName'),
485
                    api_get_setting('administratorSurname'),
486
                    null,
487
                    PERSON_NAME_EMAIL_ADDRESS
488
                );
489
                $email_admin = api_get_setting('emailAdministrator');
490
491
                $url = api_get_path(WEB_PATH);
492
                if (api_is_multiple_url_enabled()) {
493
                    $access_url_id = api_get_current_access_url_id();
494
                    if ($access_url_id != -1) {
495
                        $urlInfo = api_get_access_url($access_url_id);
496
                        if ($urlInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $urlInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
497
                            $url = $urlInfo['url'];
498
                        }
499
                    }
500
                }
501
502
                $tplContent = new Template(
503
                    null,
504
                    false,
505
                    false,
506
                    false,
507
                    false,
508
                    false
509
                );
510
                // variables for the default template
511
                $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
512
                $tplContent->assign('login_name', $loginName);
513
                $tplContent->assign('original_password', stripslashes($original_password));
514
                $tplContent->assign('mailWebPath', $url);
515
                $tplContent->assign('new_user', $user);
516
517
                $layoutContent = $tplContent->get_template('mail/content_registration_platform.tpl');
518
                $emailBody = $tplContent->fetch($layoutContent);
519
520
                $userInfo = api_get_user_info($userId);
521
                $mailTemplateManager = new MailTemplateManager();
522
523
                /* MANAGE EVENT WITH MAIL */
524
                if (EventsMail::check_if_using_class('user_registration')) {
525
                    $values["about_user"] = $return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$values was never initialized. Although not strictly required by PHP, it is generally a good practice to add $values = array(); before regardless.
Loading history...
526
                    $values["password"] = $original_password;
527
                    $values["send_to"] = [$return];
528
                    $values["prior_lang"] = null;
529
                    EventsDispatcher::events('user_registration', $values);
530
                } else {
531
                    $phoneNumber = isset($extra['mobile_phone_number']) ? $extra['mobile_phone_number'] : null;
532
                    $additionalParameters = [
533
                        'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
534
                        'userId' => $return,
535
                        'mobilePhoneNumber' => $phoneNumber,
536
                        'password' => $original_password,
537
                    ];
538
539
                    $emailBodyTemplate = '';
540
                    if (!empty($emailTemplate)) {
541
                        if (isset($emailTemplate['content_registration_platform.tpl']) &&
542
                            !empty($emailTemplate['content_registration_platform.tpl'])
543
                        ) {
544
                            $emailBodyTemplate = $mailTemplateManager->parseTemplate(
545
                                $emailTemplate['content_registration_platform.tpl'],
546
                                $userInfo
547
                            );
548
                        }
549
                    }
550
551
                    $twoEmail = api_get_configuration_value('send_two_inscription_confirmation_mail');
552
                    if ($twoEmail === true) {
553
                        $layoutContent = $tplContent->get_template('mail/new_user_first_email_confirmation.tpl');
554
                        $emailBody = $tplContent->fetch($layoutContent);
555
556
                        if (!empty($emailBodyTemplate) &&
557
                            isset($emailTemplate['new_user_first_email_confirmation.tpl']) &&
558
                            !empty($emailTemplate['new_user_first_email_confirmation.tpl'])
559
                        ) {
560
                            $emailBody = $mailTemplateManager->parseTemplate(
561
                                $emailTemplate['new_user_first_email_confirmation.tpl'],
562
                                $userInfo
563
                            );
564
                        }
565
566
                        api_mail_html(
567
                            $recipient_name,
568
                            $email,
569
                            $emailSubject,
570
                            $emailBody,
571
                            $sender_name,
572
                            $email_admin,
573
                            null,
574
                            null,
575
                            null,
576
                            $additionalParameters,
577
                            $creatorEmail
578
                        );
579
580
                        $layoutContent = $tplContent->get_template('mail/new_user_second_email_confirmation.tpl');
581
                        $emailBody = $tplContent->fetch($layoutContent);
582
583
                        if (!empty($emailBodyTemplate) &&
584
                            isset($emailTemplate['new_user_second_email_confirmation.tpl']) &&
585
                            !empty($emailTemplate['new_user_second_email_confirmation.tpl'])
586
                        ) {
587
                            $emailBody = $mailTemplateManager->parseTemplate(
588
                                $emailTemplate['new_user_second_email_confirmation.tpl'],
589
                                $userInfo
590
                            );
591
                        }
592
593
                        api_mail_html(
594
                            $recipient_name,
595
                            $email,
596
                            $emailSubject,
597
                            $emailBody,
598
                            $sender_name,
599
                            $email_admin,
600
                            null,
601
                            null,
602
                            null,
603
                            $additionalParameters,
604
                            $creatorEmail
605
                        );
606
                    } else {
607
                        if (!empty($emailBodyTemplate)) {
608
                            $emailBody = $emailBodyTemplate;
609
                        }
610
                        $sendToInbox = api_get_configuration_value('send_inscription_msg_to_inbox');
611
                        if ($sendToInbox) {
612
                            $adminList = self::get_all_administrators();
613
                            $senderId = 1;
614
                            if (!empty($adminList)) {
615
                                $adminInfo = current($adminList);
616
                                $senderId = $adminInfo['user_id'];
617
                            }
618
619
                            MessageManager::send_message_simple(
620
                                $userId,
621
                                $emailSubject,
622
                                $emailBody,
623
                                $senderId
624
                            );
625
                        } else {
626
                            api_mail_html(
627
                                $recipient_name,
628
                                $email,
629
                                $emailSubject,
630
                                $emailBody,
631
                                $sender_name,
632
                                $email_admin,
633
                                null,
634
                                null,
635
                                null,
636
                                $additionalParameters,
637
                                $creatorEmail
638
                            );
639
                        }
640
                    }
641
642
                    $notification = api_get_configuration_value('send_notification_when_user_added');
643
                    if (!empty($notification) && isset($notification['admins']) && is_array($notification['admins'])) {
644
                        foreach ($notification['admins'] as $adminId) {
645
                            $emailSubjectToAdmin = get_lang('UserAdded').': '.api_get_person_name($firstName, $lastName);
646
                            MessageManager::send_message_simple($adminId, $emailSubjectToAdmin, $emailBody, $userId);
647
                        }
648
                    }
649
                }
650
651
                if ($sendEmailToAllAdmins) {
652
                    $adminList = self::get_all_administrators();
653
654
                    $tplContent = new Template(
655
                        null,
656
                        false,
657
                        false,
658
                        false,
659
                        false,
660
                        false
661
                    );
662
                    // variables for the default template
663
                    $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
664
                    $tplContent->assign('user_added', $user);
665
                    $renderer = FormValidator::getDefaultRenderer();
666
                    // Form template
667
                    $elementTemplate = ' {label}: {element} <br />';
668
                    $renderer->setElementTemplate($elementTemplate);
669
                    /** @var FormValidator $form */
670
                    $form->freeze(null, $elementTemplate);
671
                    $form->removeElement('submit');
672
                    $formData = $form->returnForm();
673
                    $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId();
674
                    $tplContent->assign('link', Display::url($url, $url));
675
                    $tplContent->assign('form', $formData);
676
677
                    $layoutContent = $tplContent->get_template('mail/content_registration_platform_to_admin.tpl');
678
                    $emailBody = $tplContent->fetch($layoutContent);
679
680
                    if (!empty($emailBodyTemplate) &&
681
                        isset($emailTemplate['content_registration_platform_to_admin.tpl']) &&
682
                        !empty($emailTemplate['content_registration_platform_to_admin.tpl'])
683
                    ) {
684
                        $emailBody = $mailTemplateManager->parseTemplate(
685
                            $emailTemplate['content_registration_platform_to_admin.tpl'],
686
                            $userInfo
687
                        );
688
                    }
689
690
                    $subject = get_lang('UserAdded');
691
692
                    foreach ($adminList as $adminId => $data) {
693
                        MessageManager::send_message_simple(
694
                            $adminId,
695
                            $subject,
696
                            $emailBody,
697
                            $userId
698
                        );
699
                    }
700
                }
701
                /* ENDS MANAGE EVENT WITH MAIL */
702
            }
703
704
            if (!empty($hook)) {
705
                $hook->setEventData([
706
                    'return' => $userId,
707
                    'originalPassword' => $original_password,
708
                ]);
709
                $hook->notifyCreateUser(HOOK_EVENT_TYPE_POST);
710
            }
711
            Event::addEvent(LOG_USER_CREATE, LOG_USER_ID, $userId);
712
        } else {
713
            Display::addFlash(
714
                Display::return_message(get_lang('ErrorContactPlatformAdmin'))
715
            );
716
717
            return false;
718
        }
719
720
        return $return;
721
    }
722
723
    /**
724
     * Ensure the CAS-authenticated user exists in the database.
725
     *
726
     * @param $casUser string the CAS user identifier
727
     *
728
     * @throws Exception if more than one user share the same CAS user identifier
729
     *
730
     * @return string|bool the recognised user login name or false if not found
731
     */
732
    public static function casUserLoginName($casUser)
733
    {
734
        $loginName = false;
735
736
        // look inside the casUser extra field
737
        if (UserManager::is_extra_field_available('cas_user')) {
738
            $valueModel = new ExtraFieldValue('user');
739
            $itemList = $valueModel->get_item_id_from_field_variable_and_field_value(
740
                'cas_user',
741
                $casUser,
742
                false,
743
                false,
744
                true
745
            );
746
            if (false !== $itemList) {
747
                // at least one user has $casUser in the 'cas_user' extra field
748
                // we attempt to load each candidate user because there might be deleted ones
749
                // (extra field values of a deleted user might remain)
750
                foreach ($itemList as $item) {
751
                    $userId = intval($item['item_id']);
752
                    $user = UserManager::getRepository()->find($userId);
753
                    if (!is_null($user)) {
754
                        if (false === $loginName) {
755
                            $loginName = $user->getUsername();
756
                        } else {
757
                            throw new Exception(get_lang('MoreThanOneUserMatched'));
758
                        }
759
                    }
760
                }
761
            }
762
        }
763
764
        if (false === $loginName) {
765
            // no matching 'cas_user' extra field value, or no such extra field
766
            // falling back to the old behaviour: $casUser must be the login name
767
            $userId = UserManager::get_user_id_from_username($casUser);
768
            if (false !== $userId) {
769
                $loginName = $casUser;
770
            }
771
        }
772
773
        return $loginName;
774
    }
775
776
    /**
777
     * Checks the availability of extra field 'cas_user'
778
     * and creates it if missing.
779
     *
780
     * @throws Exception on failure
781
     */
782
    public static function ensureCASUserExtraFieldExists()
783
    {
784
        if (!UserManager::is_extra_field_available('cas_user')) {
785
            $extraField = new ExtraField('user');
786
            if (false === $extraField->save(
787
                    [
788
                        'variable' => 'cas_user',
789
                        'field_type' => ExtraField::FIELD_TYPE_TEXT,
790
                        'display_text' => get_lang('CAS User Identifier'),
791
                        'visible_to_self' => true,
792
                        'filter' => true,
793
                    ]
794
                )) {
795
                throw new Exception(get_lang('FailedToCreateExtraFieldCasUser'));
796
            }
797
        }
798
    }
799
800
    /**
801
     * Create a CAS-authenticated user from scratch, from its CAS user identifier, with temporary default values.
802
     *
803
     * @param string $casUser the CAS user identifier
804
     *
805
     * @throws Exception on error
806
     *
807
     * @return string the login name of the new user
808
     */
809
    public static function createCASAuthenticatedUserFromScratch($casUser)
810
    {
811
        self::ensureCASUserExtraFieldExists();
812
813
        $loginName = 'cas_user_'.$casUser;
814
        $defaultValue = get_lang("EditInProfile");
815
        require_once __DIR__.'/../../auth/external_login/functions.inc.php';
816
        $userId = external_add_user(
817
            [
818
                'username' => $loginName,
819
                'auth_source' => CAS_AUTH_SOURCE,
820
                'firstname' => $defaultValue,
821
                'lastname' => $defaultValue,
822
                'email' => $defaultValue,
823
            ]
824
        );
825
        if (false === $userId) {
826
            throw new Exception(get_lang('FailedUserCreation'));
827
        }
828
        // Not checking function update_extra_field_value return value because not reliable
829
        self::update_extra_field_value($userId, 'cas_user', $casUser);
830
831
        return $loginName;
832
    }
833
834
    /**
835
     * Create a CAS-authenticated user from LDAP, from its CAS user identifier.
836
     *
837
     * @param $casUser
838
     *
839
     * @throws Exception
840
     *
841
     * @return string login name of the new user
842
     */
843
    public static function createCASAuthenticatedUserFromLDAP($casUser)
844
    {
845
        self::ensureCASUserExtraFieldExists();
846
847
        require_once __DIR__.'/../../auth/external_login/ldap.inc.php';
848
        $login = extldapCasUserLogin($casUser);
849
        if (false !== $login) {
850
            $ldapUser = extldap_authenticate($login, 'nopass', true);
851
            if (false !== $ldapUser) {
852
                require_once __DIR__.'/../../auth/external_login/functions.inc.php';
853
                $user = extldap_get_chamilo_user($ldapUser);
854
                $user['username'] = $login;
855
                $user['auth_source'] = CAS_AUTH_SOURCE;
856
                $userId = external_add_user($user);
857
                if (false !== $userId) {
858
                    // Not checking function update_extra_field_value return value because not reliable
859
                    self::update_extra_field_value($userId, 'cas_user', $casUser);
860
861
                    return $login;
862
                } else {
863
                    throw new Exception('Could not create the new user '.$login);
864
                }
865
            } else {
866
                throw new Exception('Could not load the new user from LDAP using its login '.$login);
0 ignored issues
show
Bug introduced by
Are you sure $login of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

866
                throw new Exception('Could not load the new user from LDAP using its login './** @scrutinizer ignore-type */ $login);
Loading history...
867
            }
868
        } else {
869
            throw new Exception('Could not find the new user from LDAP using its cas user identifier '.$casUser);
870
        }
871
    }
872
873
    /**
874
     * updates user record in database from its LDAP record
875
     * copies relevant LDAP attribute values : firstname, lastname and email.
876
     *
877
     * @param $login string the user login name
878
     *
879
     * @throws Exception when the user login name is not found in the LDAP or in the database
880
     */
881
    public static function updateUserFromLDAP($login)
882
    {
883
        require_once __DIR__.'/../../auth/external_login/ldap.inc.php';
884
885
        $ldapUser = extldap_authenticate($login, 'nopass', true);
886
        if (false === $ldapUser) {
887
            throw new Exception(get_lang('NoSuchUserInLDAP'));
888
        }
889
890
        $user = extldap_get_chamilo_user($ldapUser);
891
        $userInfo = api_get_user_info_from_username($login);
892
        if (false === $userInfo) {
893
            throw new Exception(get_lang('NoSuchUserInInternalDatabase'));
894
        }
895
896
        $userId = UserManager::update_user(
897
            $userInfo['user_id'],
898
            $user["firstname"],
899
            $user["lastname"],
900
            $login,
901
            null,
902
            $userInfo['auth_source'],
903
            $user["email"],
904
            $userInfo['status'],
905
            $userInfo['official_code'],
906
            $userInfo['phone'],
907
            $userInfo['picture_uri'],
908
            $userInfo['expiration_date'],
909
            $userInfo['active'],
910
            $userInfo['creator_id'],
911
            $userInfo['hr_dept_id'],
912
            null,
913
            $userInfo['language']
914
        );
915
        if (false === $userId) {
916
            throw new Exception(get_lang('CouldNotUpdateUser'));
917
        }
918
    }
919
920
    /**
921
     * Can user be deleted? This function checks whether there's a course
922
     * in which the given user is the
923
     * only course administrator. If that is the case, the user can't be
924
     * deleted because the course would remain without a course admin.
925
     *
926
     * @param int $user_id The user id
927
     *
928
     * @return bool true if user can be deleted
929
     *
930
     * @assert (null) === false
931
     * @assert (-1) === false
932
     * @assert ('abc') === false
933
     */
934
    public static function canDeleteUser($user_id)
935
    {
936
        $deny = api_get_configuration_value('deny_delete_users');
937
938
        if ($deny) {
939
            return false;
940
        }
941
942
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
943
        $user_id = (int) $user_id;
944
945
        if (empty($user_id)) {
946
            return false;
947
        }
948
949
        $res = Database::query(
950
            "SELECT c_id FROM $table_course_user WHERE status = 1 AND user_id = $user_id"
951
        );
952
        while ($course = Database::fetch_assoc($res)) {
953
            $sql = Database::query(
954
                "SELECT COUNT(id) number FROM $table_course_user WHERE status = 1 AND c_id = {$course['c_id']}"
955
            );
956
            $res2 = Database::fetch_assoc($sql);
957
958
            if ($res2['number'] == 1) {
959
                return false;
960
            }
961
        }
962
963
        return true;
964
    }
965
966
    /**
967
     * Delete a user from the platform, and all its belongings. This is a
968
     * very dangerous function that should only be accessible by
969
     * super-admins. Other roles should only be able to disable a user,
970
     * which removes access to the platform but doesn't delete anything.
971
     *
972
     * @param int The ID of th user to be deleted
973
     *
974
     * @throws Exception
975
     *
976
     * @return bool true if user is successfully deleted, false otherwise
977
     * @assert (null) === false
978
     * @assert ('abc') === false
979
     */
980
    public static function delete_user($user_id)
981
    {
982
        $user_id = (int) $user_id;
983
984
        if (empty($user_id)) {
985
            return false;
986
        }
987
988
        if (!self::canDeleteUser($user_id)) {
989
            return false;
990
        }
991
992
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
993
        $usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER);
994
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
995
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
996
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
997
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
998
        $table_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
999
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1000
        $table_group = Database::get_course_table(TABLE_GROUP_USER);
1001
        $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1002
1003
        // Unsubscribe the user from all groups in all his courses
1004
        $sql = "SELECT c.id
1005
                FROM $table_course c
1006
                INNER JOIN $table_course_user cu
1007
                ON (c.id = cu.c_id)
1008
                WHERE
1009
                    cu.user_id = '".$user_id."' AND
1010
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1011
                ";
1012
1013
        $res = Database::query($sql);
1014
        while ($course = Database::fetch_object($res)) {
1015
            $sql = "DELETE FROM $table_group
1016
                    WHERE c_id = {$course->id} AND user_id = $user_id";
1017
            Database::query($sql);
1018
        }
1019
1020
        // Unsubscribe user from usergroup_rel_user
1021
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
1022
        Database::query($sql);
1023
1024
        // Unsubscribe user from all courses
1025
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
1026
        Database::query($sql);
1027
1028
        // Unsubscribe user from all courses in sessions
1029
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
1030
        Database::query($sql);
1031
1032
        // If the user was added as a id_coach then set the current admin as coach see BT#
1033
        $currentUserId = api_get_user_id();
1034
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
1035
                WHERE id_coach = '".$user_id."'";
1036
        Database::query($sql);
1037
1038
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
1039
                WHERE session_admin_id = '".$user_id."'";
1040
        Database::query($sql);
1041
1042
        // Unsubscribe user from all sessions
1043
        $sql = "DELETE FROM $table_session_user
1044
                WHERE user_id = '".$user_id."'";
1045
        Database::query($sql);
1046
1047
        if (api_get_configuration_value('plugin_redirection_enabled')) {
1048
            RedirectionPlugin::deleteUserRedirection($user_id);
1049
        }
1050
1051
        $user_info = api_get_user_info($user_id);
1052
1053
        try {
1054
            self::deleteUserFiles($user_id);
1055
        } catch (Exception $exception) {
1056
            error_log('Delete user exception: '.$exception->getMessage());
1057
        }
1058
1059
        // Delete the personal course categories
1060
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
1061
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
1062
        Database::query($sql);
1063
1064
        // Delete user from the admin table
1065
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
1066
        Database::query($sql);
1067
1068
        // Delete the personal agenda-items from this user
1069
        $agenda_table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
1070
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
1071
        Database::query($sql);
1072
1073
        $gradebook_results_table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
1074
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
1075
        Database::query($sql);
1076
1077
        $extraFieldValue = new ExtraFieldValue('user');
1078
        $extraFieldValue->deleteValuesByItem($user_id);
1079
1080
        UrlManager::deleteUserFromAllUrls($user_id);
1081
1082
        if (api_get_setting('allow_social_tool') === 'true') {
1083
            $userGroup = new UserGroup();
1084
            //Delete user from portal groups
1085
            $group_list = $userGroup->get_groups_by_user($user_id);
1086
            if (!empty($group_list)) {
1087
                foreach ($group_list as $group_id => $data) {
1088
                    $userGroup->delete_user_rel_group($user_id, $group_id);
1089
                }
1090
            }
1091
1092
            // Delete user from friend lists
1093
            SocialManager::remove_user_rel_user($user_id, true);
1094
        }
1095
1096
        // Removing survey invitation
1097
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
1098
1099
        // Delete students works
1100
        $sql = "DELETE FROM $table_work WHERE user_id = $user_id AND c_id <> 0";
1101
        Database::query($sql);
1102
1103
        $sql = "UPDATE c_item_property SET to_user_id = NULL
1104
                WHERE to_user_id = '".$user_id."'";
1105
        Database::query($sql);
1106
1107
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
1108
                WHERE insert_user_id = '".$user_id."'";
1109
        Database::query($sql);
1110
1111
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
1112
                WHERE lastedit_user_id = '".$user_id."'";
1113
        Database::query($sql);
1114
1115
        // Skills
1116
        $em = Database::getManager();
1117
1118
        $criteria = ['user' => $user_id];
1119
        $skills = $em->getRepository('ChamiloCoreBundle:SkillRelUser')->findBy($criteria);
1120
        if ($skills) {
1121
            /** @var SkillRelUser $skill */
1122
            foreach ($skills as $skill) {
1123
                $comments = $skill->getComments();
1124
                if ($comments) {
1125
                    /** @var SkillRelUserComment $comment */
1126
                    foreach ($comments as $comment) {
1127
                        $em->remove($comment);
1128
                    }
1129
                }
1130
                $em->remove($skill);
1131
            }
1132
            $em->flush();
1133
        }
1134
1135
        // ExtraFieldSavedSearch
1136
        $criteria = ['user' => $user_id];
1137
        $searchList = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findBy($criteria);
1138
        if ($searchList) {
1139
            foreach ($searchList as $search) {
1140
                $em->remove($search);
1141
            }
1142
            $em->flush();
1143
        }
1144
1145
        $connection = Database::getManager()->getConnection();
1146
        $tableExists = $connection->getSchemaManager()->tablesExist(['plugin_bbb_room']);
1147
        if ($tableExists) {
1148
            // Delete user from database
1149
            $sql = "DELETE FROM plugin_bbb_room WHERE participant_id = $user_id";
1150
            Database::query($sql);
1151
        }
1152
1153
        // Delete user/ticket relationships :(
1154
        $tableExists = $connection->getSchemaManager()->tablesExist(['ticket_ticket']);
1155
        if ($tableExists) {
1156
            TicketManager::deleteUserFromTicketSystem($user_id);
1157
        }
1158
1159
        $tableExists = $connection->getSchemaManager()->tablesExist(['c_lp_category_user']);
1160
        if ($tableExists) {
1161
            $sql = "DELETE FROM c_lp_category_user WHERE user_id = $user_id";
1162
            Database::query($sql);
1163
        }
1164
1165
        $app_plugin = new AppPlugin();
1166
        $app_plugin->performActionsWhenDeletingItem('user', $user_id);
1167
1168
        // Delete user from database
1169
        $sql = "DELETE FROM $table_user WHERE id = '".$user_id."'";
1170
        Database::query($sql);
1171
1172
        // Add event to system log
1173
        $user_id_manager = api_get_user_id();
1174
1175
        Event::addEvent(
1176
            LOG_USER_DELETE,
1177
            LOG_USER_ID,
1178
            $user_id,
1179
            api_get_utc_datetime(),
1180
            $user_id_manager
1181
        );
1182
1183
        Event::addEvent(
1184
            LOG_USER_DELETE,
1185
            LOG_USER_OBJECT,
1186
            $user_info,
1187
            api_get_utc_datetime(),
1188
            $user_id_manager
1189
        );
1190
        $cacheAvailable = api_get_configuration_value('apc');
1191
        if ($cacheAvailable === true) {
1192
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1193
            if (apcu_exists($apcVar)) {
1194
                apcu_delete($apcVar);
1195
            }
1196
        }
1197
1198
        return true;
1199
    }
1200
1201
    /**
1202
     * Deletes users completely. Can be called either as:
1203
     * - UserManager::delete_users(1, 2, 3); or
1204
     * - UserManager::delete_users(array(1, 2, 3));.
1205
     *
1206
     * @param array|int $ids
1207
     *
1208
     * @return bool True if at least one user was successfuly deleted. False otherwise.
1209
     *
1210
     * @author Laurent Opprecht
1211
     *
1212
     * @uses \UserManager::delete_user() to actually delete each user
1213
     * @assert (null) === false
1214
     * @assert (-1) === false
1215
     * @assert (array(-1)) === false
1216
     */
1217
    public static function delete_users($ids = [])
1218
    {
1219
        $result = false;
1220
        $ids = is_array($ids) ? $ids : func_get_args();
1221
        if (!is_array($ids) || count($ids) == 0) {
1222
            return false;
1223
        }
1224
        $ids = array_map('intval', $ids);
1225
        foreach ($ids as $id) {
1226
            if (empty($id) || $id < 1) {
1227
                continue;
1228
            }
1229
            $deleted = self::delete_user($id);
1230
            $result = $deleted || $result;
1231
        }
1232
1233
        return $result;
1234
    }
1235
1236
    /**
1237
     * Disable users. Can be called either as:
1238
     * - UserManager::deactivate_users(1, 2, 3);
1239
     * - UserManager::deactivate_users(array(1, 2, 3));.
1240
     *
1241
     * @param array|int $ids
1242
     *
1243
     * @return bool
1244
     *
1245
     * @author Laurent Opprecht
1246
     * @assert (null) === false
1247
     * @assert (array(-1)) === false
1248
     */
1249
    public static function deactivate_users($ids = [])
1250
    {
1251
        if (empty($ids)) {
1252
            return false;
1253
        }
1254
1255
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1256
1257
        $ids = is_array($ids) ? $ids : func_get_args();
1258
        $ids = array_map('intval', $ids);
1259
        $ids = implode(',', $ids);
1260
1261
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
1262
        $r = Database::query($sql);
1263
        if ($r !== false) {
1264
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
1265
1266
            return true;
1267
        }
1268
1269
        return false;
1270
    }
1271
1272
    /**
1273
     * Enable users. Can be called either as:
1274
     * - UserManager::activate_users(1, 2, 3);
1275
     * - UserManager::activate_users(array(1, 2, 3));.
1276
     *
1277
     * @param array|int IDs of the users to enable
1278
     *
1279
     * @return bool
1280
     *
1281
     * @author Laurent Opprecht
1282
     * @assert (null) === false
1283
     * @assert (array(-1)) === false
1284
     */
1285
    public static function activate_users($ids = [])
1286
    {
1287
        if (empty($ids)) {
1288
            return false;
1289
        }
1290
1291
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1292
1293
        $ids = is_array($ids) ? $ids : func_get_args();
1294
        $ids = array_map('intval', $ids);
1295
        $ids = implode(',', $ids);
1296
1297
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
1298
        $r = Database::query($sql);
1299
        if ($r !== false) {
1300
            Event::addEvent(LOG_USER_ENABLE, LOG_USER_ID, $ids);
1301
1302
            return true;
1303
        }
1304
1305
        return false;
1306
    }
1307
1308
    /**
1309
     * Update user information with new openid.
1310
     *
1311
     * @param int    $user_id
1312
     * @param string $openid
1313
     *
1314
     * @return bool true if the user information was updated
1315
     * @assert (false,'') === false
1316
     * @assert (-1,'') === false
1317
     */
1318
    public static function update_openid($user_id, $openid)
1319
    {
1320
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1321
        if ($user_id != strval(intval($user_id))) {
1322
            return false;
1323
        }
1324
        if ($user_id === false) {
1325
            return false;
1326
        }
1327
        $sql = "UPDATE $table_user SET
1328
                openid='".Database::escape_string($openid)."'";
1329
        $sql .= " WHERE id= $user_id";
1330
1331
        if (Database::query($sql) !== false) {
1332
            return true;
1333
        }
1334
1335
        return false;
1336
    }
1337
1338
    /**
1339
     * Update user information with all the parameters passed to this function.
1340
     *
1341
     * @param int    $user_id         The ID of the user to be updated
1342
     * @param string $firstname       The user's firstname
1343
     * @param string $lastname        The user's lastname
1344
     * @param string $username        The user's username (login)
1345
     * @param string $password        The user's password
1346
     * @param string $auth_source     The authentication source (default: "platform")
1347
     * @param string $email           The user's e-mail address
1348
     * @param int    $status          The user's status
1349
     * @param string $official_code   The user's official code (usually just an internal institutional code)
1350
     * @param string $phone           The user's phone number
1351
     * @param string $picture_uri     The user's picture URL (internal to the Chamilo directory)
1352
     * @param string $expiration_date The date at which this user will be automatically disabled
1353
     * @param int    $active          Whether this account needs to be enabled (1) or disabled (0)
1354
     * @param int    $creator_id      The user ID of the person who registered this user (optional, defaults to null)
1355
     * @param int    $hr_dept_id      The department of HR in which the user is registered (optional, defaults to 0)
1356
     * @param array  $extra           Additional fields to add to this user as extra fields (defaults to null)
1357
     * @param string $language        The language to which the user account will be set
1358
     * @param string $encrypt_method  The cipher method. This parameter is deprecated. It will use the system's default
1359
     * @param bool   $send_email      Whether to send an e-mail to the user after the update is complete
1360
     * @param int    $reset_password  Method used to reset password (0, 1, 2 or 3 - see usage examples for details)
1361
     * @param string $address
1362
     * @param array  $emailTemplate
1363
     *
1364
     * @return bool|int False on error, or the user ID if the user information was updated
1365
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
1366
     */
1367
    public static function update_user(
1368
        $user_id,
1369
        $firstname,
1370
        $lastname,
1371
        $username,
1372
        $password = null,
1373
        $auth_source = null,
1374
        $email,
1375
        $status,
1376
        $official_code,
1377
        $phone,
1378
        $picture_uri,
1379
        $expiration_date,
1380
        $active,
1381
        $creator_id = null,
1382
        $hr_dept_id = 0,
1383
        $extra = null,
1384
        $language = 'english',
1385
        $encrypt_method = '',
1386
        $send_email = false,
1387
        $reset_password = 0,
1388
        $address = null,
1389
        $emailTemplate = []
1390
    ) {
1391
        $hook = HookUpdateUser::create();
1392
        if (!empty($hook)) {
1393
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_PRE);
1394
        }
1395
        $original_password = $password;
1396
        $user_id = (int) $user_id;
1397
        $creator_id = (int) $creator_id;
1398
1399
        if (empty($user_id)) {
1400
            return false;
1401
        }
1402
1403
        $userManager = self::getManager();
1404
        /** @var User $user */
1405
        $user = self::getRepository()->find($user_id);
1406
1407
        if (empty($user)) {
1408
            return false;
1409
        }
1410
1411
        if ($reset_password == 0) {
1412
            $password = null;
1413
            $auth_source = $user->getAuthSource();
1414
        } elseif ($reset_password == 1) {
1415
            $original_password = $password = api_generate_password();
1416
            $auth_source = PLATFORM_AUTH_SOURCE;
1417
        } elseif ($reset_password == 2) {
1418
            //$password = $password;
1419
            $auth_source = PLATFORM_AUTH_SOURCE;
1420
        } elseif ($reset_password == 3) {
1421
            //$password = $password;
1422
            //$auth_source = $auth_source;
1423
        }
1424
1425
        // Checking the user language
1426
        $languages = api_get_languages();
1427
        if (!in_array($language, $languages['folder'])) {
1428
            $language = api_get_setting('platformLanguage');
1429
        }
1430
1431
        $change_active = 0;
1432
        $isUserActive = $user->getActive();
1433
        if ($isUserActive != $active) {
1434
            $change_active = 1;
1435
        }
1436
1437
        $originalUsername = $user->getUsername();
1438
1439
        // If username is different from original then check if it exists.
1440
        if ($originalUsername !== $username) {
1441
            $available = self::is_username_available($username);
1442
            if ($available === false) {
1443
                return false;
1444
            }
1445
        }
1446
1447
        if (!empty($expiration_date)) {
1448
            $expiration_date = api_get_utc_datetime($expiration_date);
1449
            $expiration_date = new \DateTime(
1450
                $expiration_date,
1451
                new DateTimeZone('UTC')
1452
            );
1453
        }
1454
1455
        $user
1456
            ->setLastname($lastname)
1457
            ->setFirstname($firstname)
1458
            ->setUsername($username)
1459
            ->setStatus($status)
1460
            ->setAuthSource($auth_source)
1461
            ->setLanguage($language)
1462
            ->setEmail($email)
1463
            ->setOfficialCode($official_code)
1464
            ->setPhone($phone)
1465
            ->setAddress($address)
1466
            ->setPictureUri($picture_uri)
1467
            ->setExpirationDate($expiration_date)
1468
            ->setActive($active)
1469
            ->setEnabled($active)
1470
            ->setHrDeptId($hr_dept_id)
1471
        ;
1472
1473
        if (!is_null($password)) {
1474
            $user->setPlainPassword($password);
1475
            Event::addEvent(LOG_USER_PASSWORD_UPDATE, LOG_USER_ID, $user_id);
1476
        }
1477
1478
        $userManager->updateUser($user, true);
1479
        Event::addEvent(LOG_USER_UPDATE, LOG_USER_ID, $user_id);
1480
1481
        if ($change_active == 1) {
1482
            if ($active == 1) {
1483
                $event_title = LOG_USER_ENABLE;
1484
            } else {
1485
                $event_title = LOG_USER_DISABLE;
1486
            }
1487
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
1488
        }
1489
1490
        if (is_array($extra) && count($extra) > 0) {
1491
            $res = true;
1492
            foreach ($extra as $fname => $fvalue) {
1493
                $res = $res && self::update_extra_field_value(
1494
                    $user_id,
1495
                    $fname,
1496
                    $fvalue
1497
                );
1498
            }
1499
        }
1500
1501
        if (!empty($email) && $send_email) {
1502
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
1503
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('YourReg').' '.api_get_setting('siteName');
1504
            $sender_name = api_get_person_name(
1505
                api_get_setting('administratorName'),
1506
                api_get_setting('administratorSurname'),
1507
                null,
1508
                PERSON_NAME_EMAIL_ADDRESS
1509
            );
1510
            $email_admin = api_get_setting('emailAdministrator');
1511
            $url = api_get_path(WEB_PATH);
1512
            if (api_is_multiple_url_enabled()) {
1513
                $access_url_id = api_get_current_access_url_id();
1514
                if ($access_url_id != -1) {
1515
                    $url = api_get_access_url($access_url_id);
1516
                    $url = $url['url'];
1517
                }
1518
            }
1519
1520
            $tplContent = new Template(
1521
                null,
1522
                false,
1523
                false,
1524
                false,
1525
                false,
1526
                false
1527
            );
1528
            // variables for the default template
1529
            $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstname, $lastname)));
1530
            $tplContent->assign('login_name', $username);
1531
1532
            $originalPassword = '';
1533
            if ($reset_password > 0) {
1534
                $originalPassword = stripslashes($original_password);
1535
            }
1536
            $tplContent->assign('original_password', $originalPassword);
1537
            $tplContent->assign('portal_url', $url);
1538
1539
            $layoutContent = $tplContent->get_template('mail/user_edit_content.tpl');
1540
            $emailBody = $tplContent->fetch($layoutContent);
1541
1542
            $mailTemplateManager = new MailTemplateManager();
1543
1544
            if (!empty($emailTemplate) &&
1545
                isset($emailTemplate['user_edit_content.tpl']) &&
1546
                !empty($emailTemplate['user_edit_content.tpl'])
1547
            ) {
1548
                $userInfo = api_get_user_info($user_id);
1549
                $emailBody = $mailTemplateManager->parseTemplate($emailTemplate['user_edit_content.tpl'], $userInfo);
1550
            }
1551
1552
            $creatorInfo = api_get_user_info($creator_id);
1553
            $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
1554
1555
            api_mail_html(
1556
                $recipient_name,
1557
                $email,
1558
                $emailsubject,
1559
                $emailBody,
1560
                $sender_name,
1561
                $email_admin,
1562
                null,
1563
                null,
1564
                null,
1565
                null,
1566
                $creatorEmail
1567
            );
1568
        }
1569
1570
        if (!empty($hook)) {
1571
            $hook->setEventData(['user' => $user]);
1572
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_POST);
1573
        }
1574
1575
        $cacheAvailable = api_get_configuration_value('apc');
1576
        if ($cacheAvailable === true) {
1577
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1578
            if (apcu_exists($apcVar)) {
1579
                apcu_delete($apcVar);
1580
            }
1581
        }
1582
1583
        return $user->getId();
1584
    }
1585
1586
    /**
1587
     * Disables a user.
1588
     *
1589
     * @param int User id
1590
     *
1591
     * @return bool
1592
     *
1593
     * @uses \UserManager::change_active_state() to actually disable the user
1594
     * @assert (0) === false
1595
     */
1596
    public static function disable($user_id)
1597
    {
1598
        if (empty($user_id)) {
1599
            return false;
1600
        }
1601
        self::change_active_state($user_id, 0);
1602
1603
        return true;
1604
    }
1605
1606
    /**
1607
     * Enable a user.
1608
     *
1609
     * @param int User id
1610
     *
1611
     * @return bool
1612
     *
1613
     * @uses \UserManager::change_active_state() to actually disable the user
1614
     * @assert (0) === false
1615
     */
1616
    public static function enable($user_id)
1617
    {
1618
        if (empty($user_id)) {
1619
            return false;
1620
        }
1621
        self::change_active_state($user_id, 1);
1622
1623
        return true;
1624
    }
1625
1626
    /**
1627
     * Returns the user's id based on the original id and field name in
1628
     * the extra fields. Returns 0 if no user was found. This function is
1629
     * mostly useful in the context of a web services-based sinchronization.
1630
     *
1631
     * @param string Original user id
1632
     * @param string Original field name
1633
     *
1634
     * @return int User id
1635
     * @assert ('0','---') === 0
1636
     */
1637
    public static function get_user_id_from_original_id(
1638
        $original_user_id_value,
1639
        $original_user_id_name
1640
    ) {
1641
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1642
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1643
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1644
1645
        $original_user_id_name = Database::escape_string($original_user_id_name);
1646
        $original_user_id_value = Database::escape_string($original_user_id_value);
1647
1648
        $sql = "SELECT item_id as user_id
1649
                FROM $t_uf uf
1650
                INNER JOIN $t_ufv ufv
1651
                ON ufv.field_id = uf.id
1652
                WHERE
1653
                    variable = '$original_user_id_name' AND
1654
                    value = '$original_user_id_value' AND
1655
                    extra_field_type = $extraFieldType
1656
                ";
1657
        $res = Database::query($sql);
1658
        $row = Database::fetch_object($res);
1659
        if ($row) {
1660
            return $row->user_id;
1661
        }
1662
1663
        return 0;
1664
    }
1665
1666
    /**
1667
     * Check if a username is available.
1668
     *
1669
     * @param string $username the wanted username
1670
     *
1671
     * @return bool true if the wanted username is available
1672
     * @assert ('') === false
1673
     * @assert ('xyzxyzxyz') === true
1674
     */
1675
    public static function is_username_available($username)
1676
    {
1677
        if (empty($username)) {
1678
            return false;
1679
        }
1680
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1681
        $sql = "SELECT username FROM $table_user
1682
                WHERE username = '".Database::escape_string($username)."'";
1683
        $res = Database::query($sql);
1684
1685
        return Database::num_rows($res) == 0;
1686
    }
1687
1688
    /**
1689
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1690
     *
1691
     * @param string $firstname the first name of the user
1692
     * @param string $lastname  the last name of the user
1693
     *
1694
     * @return string suggests a username that contains only ASCII-letters and digits,
1695
     *                without check for uniqueness within the system
1696
     *
1697
     * @author Julio Montoya Armas
1698
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1699
     * @assert ('','') === false
1700
     * @assert ('a','b') === 'ab'
1701
     */
1702
    public static function create_username($firstname, $lastname)
1703
    {
1704
        if (empty($firstname) && empty($lastname)) {
1705
            return false;
1706
        }
1707
1708
        // The first letter only.
1709
        $firstname = api_substr(
1710
            preg_replace(USERNAME_PURIFIER, '', $firstname),
1711
            0,
1712
            1
1713
        );
1714
        //Looking for a space in the lastname
1715
        $pos = api_strpos($lastname, ' ');
1716
        if ($pos !== false) {
1717
            $lastname = api_substr($lastname, 0, $pos);
1718
        }
1719
1720
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1721
        $username = $firstname.$lastname;
1722
        if (empty($username)) {
1723
            $username = 'user';
1724
        }
1725
1726
        $username = URLify::transliterate($username);
1727
1728
        return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3));
1729
    }
1730
1731
    /**
1732
     * Creates a unique username, using:
1733
     * 1. the first name and the last name of a user;
1734
     * 2. an already created username but not checked for uniqueness yet.
1735
     *
1736
     * @param string $firstname The first name of a given user. If the second parameter $lastname is NULL, then this
1737
     *                          parameter is treated as username which is to be checked f
1738
     *                          or uniqueness and to be modified when it is necessary.
1739
     * @param string $lastname  the last name of the user
1740
     *
1741
     * @return string Returns a username that contains only ASCII-letters and digits and that is unique in the system.
1742
     *                Note: When the method is called several times with same parameters,
1743
     *                its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1744
     *
1745
     * @author Ivan Tcholakov, 2009
1746
     */
1747
    public static function create_unique_username($firstname, $lastname = null)
1748
    {
1749
        if (is_null($lastname)) {
1750
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1751
            // For making this method tolerant of mistakes,
1752
            // let us transliterate and purify the suggested input username anyway.
1753
            // So, instead of the sentence $username = $firstname; we place the following:
1754
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1755
        } else {
1756
            $username = self::create_username($firstname, $lastname);
1757
        }
1758
        if (!self::is_username_available($username)) {
1759
            $i = 2;
1760
            $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1761
            while (!self::is_username_available($temp_username)) {
1762
                $i++;
1763
                $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1764
            }
1765
            $username = $temp_username;
1766
        }
1767
1768
        $username = URLify::transliterate($username);
1769
1770
        return $username;
1771
    }
1772
1773
    /**
1774
     * Modifies a given username accordingly to the specification for valid characters and length.
1775
     *
1776
     * @param $username string          The input username
1777
     * @param bool $strict (optional)   When this flag is TRUE, the result is guaranteed for full compliance,
1778
     *                     otherwise compliance may be partial. The default value is FALSE.
1779
     *
1780
     * @return string the resulting purified username
1781
     */
1782
    public static function purify_username($username, $strict = false)
1783
    {
1784
        if ($strict) {
1785
            // 1. Conversion of unacceptable letters (latinian letters with accents for example)
1786
            // into ASCII letters in order they not to be totally removed.
1787
            // 2. Applying the strict purifier.
1788
            // 3. Length limitation.
1789
            if ('true' === api_get_setting('login_is_email')) {
1790
                $return = substr(preg_replace(USERNAME_PURIFIER_MAIL, '', $username), 0, USERNAME_MAX_LENGTH);
1791
            } else {
1792
                $return = substr(preg_replace(USERNAME_PURIFIER, '', $username), 0, USERNAME_MAX_LENGTH);
1793
            }
1794
1795
            return URLify::transliterate($return);
1796
        }
1797
1798
        // 1. Applying the shallow purifier.
1799
        // 2. Length limitation.
1800
        return substr(
1801
            preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username),
1802
            0,
1803
            USERNAME_MAX_LENGTH
1804
        );
1805
    }
1806
1807
    /**
1808
     * Checks whether the user id exists in the database.
1809
     *
1810
     * @param int $userId User id
1811
     *
1812
     * @return bool True if user id was found, false otherwise
1813
     */
1814
    public static function is_user_id_valid($userId)
1815
    {
1816
        $resultData = Database::select(
1817
            'COUNT(1) AS count',
1818
            Database::get_main_table(TABLE_MAIN_USER),
1819
            [
1820
                'where' => ['id = ?' => (int) $userId],
1821
            ],
1822
            'first'
1823
        );
1824
1825
        if ($resultData === false) {
1826
            return false;
1827
        }
1828
1829
        return $resultData['count'] > 0;
1830
    }
1831
1832
    /**
1833
     * Checks whether a given username matches to the specification strictly.
1834
     * The empty username is assumed here as invalid.
1835
     * Mostly this function is to be used in the user interface built-in validation routines
1836
     * for providing feedback while usernames are enterd manually.
1837
     *
1838
     * @param string $username the input username
1839
     *
1840
     * @return bool returns TRUE if the username is valid, FALSE otherwise
1841
     */
1842
    public static function is_username_valid($username)
1843
    {
1844
        return !empty($username) && $username == self::purify_username($username, true);
1845
    }
1846
1847
    /**
1848
     * Checks whether a username is empty. If the username contains whitespace characters,
1849
     * such as spaces, tabulators, newlines, etc.,
1850
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1851
     *
1852
     * @param string $username the given username
1853
     *
1854
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1855
     */
1856
    public static function is_username_empty($username)
1857
    {
1858
        return strlen(self::purify_username($username, false)) == 0;
1859
    }
1860
1861
    /**
1862
     * Checks whether a username is too long or not.
1863
     *
1864
     * @param string $username the given username, it should contain only ASCII-letters and digits
1865
     *
1866
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1867
     */
1868
    public static function is_username_too_long($username)
1869
    {
1870
        return strlen($username) > USERNAME_MAX_LENGTH;
1871
    }
1872
1873
    /**
1874
     * Get the users by ID.
1875
     *
1876
     * @param array  $ids    student ids
1877
     * @param string $active
1878
     * @param string $order
1879
     * @param string $limit
1880
     *
1881
     * @return array $result student information
1882
     */
1883
    public static function get_user_list_by_ids($ids = [], $active = null, $order = null, $limit = null)
1884
    {
1885
        if (empty($ids)) {
1886
            return [];
1887
        }
1888
1889
        $ids = is_array($ids) ? $ids : [$ids];
1890
        $ids = array_map('intval', $ids);
1891
        $ids = implode(',', $ids);
1892
1893
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1894
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1895
        if (!is_null($active)) {
1896
            $sql .= ' AND active='.($active ? '1' : '0');
1897
        }
1898
1899
        if (!is_null($order)) {
1900
            $order = Database::escape_string($order);
1901
            $sql .= ' ORDER BY '.$order;
1902
        }
1903
1904
        if (!is_null($limit)) {
1905
            $limit = Database::escape_string($limit);
1906
            $sql .= ' LIMIT '.$limit;
1907
        }
1908
1909
        $rs = Database::query($sql);
1910
        $result = [];
1911
        while ($row = Database::fetch_array($rs)) {
1912
            $result[] = $row;
1913
        }
1914
1915
        return $result;
1916
    }
1917
1918
    /**
1919
     * Get a list of users of which the given conditions match with an = 'cond'.
1920
     *
1921
     * @param array $conditions a list of condition (example : status=>STUDENT)
1922
     * @param array $order_by   a list of fields on which sort
1923
     *
1924
     * @return array an array with all users of the platform
1925
     *
1926
     * @todo security filter order by
1927
     */
1928
    public static function get_user_list(
1929
        $conditions = [],
1930
        $order_by = [],
1931
        $limit_from = false,
1932
        $limit_to = false,
1933
        $idCampus = null
1934
    ) {
1935
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1936
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1937
        $return_array = [];
1938
        $sql = "SELECT user.* FROM $user_table user ";
1939
1940
        if (api_is_multiple_url_enabled()) {
1941
            if ($idCampus) {
1942
                $urlId = $idCampus;
1943
            } else {
1944
                $urlId = api_get_current_access_url_id();
1945
            }
1946
            $sql .= " INNER JOIN $userUrlTable url_user
1947
                      ON (user.user_id = url_user.user_id)
1948
                      WHERE url_user.access_url_id = $urlId";
1949
        } else {
1950
            $sql .= " WHERE 1=1 ";
1951
        }
1952
1953
        if (count($conditions) > 0) {
1954
            foreach ($conditions as $field => $value) {
1955
                $field = Database::escape_string($field);
1956
                $value = Database::escape_string($value);
1957
                $sql .= " AND $field = '$value'";
1958
            }
1959
        }
1960
1961
        if (count($order_by) > 0) {
1962
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1963
        }
1964
1965
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1966
            $limit_from = (int) $limit_from;
1967
            $limit_to = (int) $limit_to;
1968
            $sql .= " LIMIT $limit_from, $limit_to";
1969
        }
1970
        $sql_result = Database::query($sql);
1971
        while ($result = Database::fetch_array($sql_result)) {
1972
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1973
            $return_array[] = $result;
1974
        }
1975
1976
        return $return_array;
1977
    }
1978
1979
    public static function getUserListExtraConditions(
1980
        $conditions = [],
1981
        $order_by = [],
1982
        $limit_from = false,
1983
        $limit_to = false,
1984
        $idCampus = null,
1985
        $extraConditions = '',
1986
        $getCount = false
1987
    ) {
1988
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1989
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1990
        $return_array = [];
1991
        $sql = "SELECT user.* FROM $user_table user ";
1992
1993
        if ($getCount) {
1994
            $sql = "SELECT count(user.id) count FROM $user_table user ";
1995
        }
1996
1997
        if (api_is_multiple_url_enabled()) {
1998
            if ($idCampus) {
1999
                $urlId = $idCampus;
2000
            } else {
2001
                $urlId = api_get_current_access_url_id();
2002
            }
2003
            $sql .= " INNER JOIN $userUrlTable url_user
2004
                      ON (user.user_id = url_user.user_id)
2005
                      WHERE url_user.access_url_id = $urlId";
2006
        } else {
2007
            $sql .= " WHERE 1=1 ";
2008
        }
2009
2010
        $sql .= " AND status <> ".ANONYMOUS." ";
2011
2012
        if (count($conditions) > 0) {
2013
            foreach ($conditions as $field => $value) {
2014
                $field = Database::escape_string($field);
2015
                $value = Database::escape_string($value);
2016
                $sql .= " AND $field = '$value'";
2017
            }
2018
        }
2019
2020
        $sql .= str_replace("\'", "'", Database::escape_string($extraConditions));
2021
2022
        if (!empty($order_by) && count($order_by) > 0) {
2023
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
2024
        }
2025
2026
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
2027
            $limit_from = (int) $limit_from;
2028
            $limit_to = (int) $limit_to;
2029
            $sql .= " LIMIT $limit_from, $limit_to";
2030
        }
2031
2032
        $sql_result = Database::query($sql);
2033
2034
        if ($getCount) {
2035
            $result = Database::fetch_array($sql_result);
2036
2037
            return $result['count'];
2038
        }
2039
2040
        while ($result = Database::fetch_array($sql_result)) {
2041
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
2042
            $return_array[] = $result;
2043
        }
2044
2045
        return $return_array;
2046
    }
2047
2048
    /**
2049
     * Get a list of users of which the given conditions match with a LIKE '%cond%'.
2050
     *
2051
     * @param array  $conditions       a list of condition (exemple : status=>STUDENT)
2052
     * @param array  $order_by         a list of fields on which sort
2053
     * @param bool   $simple_like      Whether we want a simple LIKE 'abc' or a LIKE '%abc%'
2054
     * @param string $condition        Whether we want the filters to be combined by AND or OR
2055
     * @param array  $onlyThisUserList
2056
     *
2057
     * @return array an array with all users of the platform
2058
     *
2059
     * @todo optional course code parameter, optional sorting parameters...
2060
     * @todo security filter order_by
2061
     */
2062
    public static function getUserListLike(
2063
        $conditions = [],
2064
        $order_by = [],
2065
        $simple_like = false,
2066
        $condition = 'AND',
2067
        $onlyThisUserList = []
2068
    ) {
2069
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
2070
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2071
        $return_array = [];
2072
        $sql_query = "SELECT user.id FROM $user_table user ";
2073
2074
        if (api_is_multiple_url_enabled()) {
2075
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
2076
        }
2077
2078
        $sql_query .= ' WHERE 1 = 1 ';
2079
        if (count($conditions) > 0) {
2080
            $temp_conditions = [];
2081
            foreach ($conditions as $field => $value) {
2082
                $field = Database::escape_string($field);
2083
                $value = Database::escape_string($value);
2084
                if ($simple_like) {
2085
                    $temp_conditions[] = $field." LIKE '$value%'";
2086
                } else {
2087
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
2088
                }
2089
            }
2090
            if (!empty($temp_conditions)) {
2091
                $sql_query .= ' AND '.implode(' '.$condition.' ', $temp_conditions);
2092
            }
2093
2094
            if (api_is_multiple_url_enabled()) {
2095
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
2096
            }
2097
        } else {
2098
            if (api_is_multiple_url_enabled()) {
2099
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
2100
            }
2101
        }
2102
2103
        if (!empty($onlyThisUserList)) {
2104
            $onlyThisUserListToString = implode("','", $onlyThisUserList);
2105
            $sql_query .= " AND user.id IN ('$onlyThisUserListToString') ";
2106
        }
2107
2108
        if (count($order_by) > 0) {
2109
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
2110
        }
2111
2112
        $sql_result = Database::query($sql_query);
2113
        while ($result = Database::fetch_array($sql_result)) {
2114
            $userInfo = api_get_user_info($result['id']);
2115
            $return_array[] = $userInfo;
2116
        }
2117
2118
        return $return_array;
2119
    }
2120
2121
    /**
2122
     * Get user picture URL or path from user ID (returns an array).
2123
     * The return format is a complete path, enabling recovery of the directory
2124
     * with dirname() or the file with basename(). This also works for the
2125
     * functions dealing with the user's productions, as they are located in
2126
     * the same directory.
2127
     *
2128
     * @param int    $id       User ID
2129
     * @param string $type     Type of path to return (can be 'system', 'web')
2130
     * @param array  $userInfo user information to avoid query the DB
2131
     *                         returns the /main/img/unknown.jpg image set it at true
2132
     *
2133
     * @return array Array of 2 elements: 'dir' and 'file' which contain
2134
     *               the dir and file as the name implies if image does not exist it will
2135
     *               return the unknow image if anonymous parameter is true if not it returns an empty array
2136
     */
2137
    public static function get_user_picture_path_by_id(
2138
        $id,
2139
        $type = 'web',
2140
        $userInfo = []
2141
    ) {
2142
        switch ($type) {
2143
            case 'system': // Base: absolute system path.
2144
                $base = api_get_path(SYS_CODE_PATH);
2145
                break;
2146
            case 'web': // Base: absolute web path.
2147
            default:
2148
                $base = api_get_path(WEB_CODE_PATH);
2149
                break;
2150
        }
2151
2152
        $anonymousPath = [
2153
            'dir' => $base.'img/',
2154
            'file' => 'unknown.jpg',
2155
            'email' => '',
2156
        ];
2157
2158
        if (empty($id) || empty($type)) {
2159
            return $anonymousPath;
2160
        }
2161
2162
        $id = (int) $id;
2163
        if (empty($userInfo)) {
2164
            $user_table = Database::get_main_table(TABLE_MAIN_USER);
2165
            $sql = "SELECT email, picture_uri FROM $user_table
2166
                    WHERE id = ".$id;
2167
            $res = Database::query($sql);
2168
2169
            if (!Database::num_rows($res)) {
2170
                return $anonymousPath;
2171
            }
2172
            $user = Database::fetch_array($res);
2173
            if (empty($user['picture_uri'])) {
2174
                return $anonymousPath;
2175
            }
2176
        } else {
2177
            $user = $userInfo;
2178
        }
2179
2180
        $pictureFilename = trim($user['picture_uri']);
2181
2182
        $dir = self::getUserPathById($id, $type);
2183
2184
        return [
2185
            'dir' => $dir,
2186
            'file' => $pictureFilename,
2187
            'email' => $user['email'],
2188
        ];
2189
    }
2190
2191
    /**
2192
     * *** READ BEFORE REVIEW THIS FUNCTION ***
2193
     * This function is a exact copy from get_user_picture_path_by_id() and it was create it to avoid
2194
     * a recursive calls for get_user_picture_path_by_id() in another functions when you update a user picture
2195
     * in same script, so you can find this function usage in update_user_picture() function.
2196
     *
2197
     * @param int    $id       User ID
2198
     * @param string $type     Type of path to return (can be 'system', 'web')
2199
     * @param array  $userInfo user information to avoid query the DB
2200
     *                         returns the /main/img/unknown.jpg image set it at true
2201
     *
2202
     * @return array Array of 2 elements: 'dir' and 'file' which contain
2203
     *               the dir and file as the name implies if image does not exist it will
2204
     *               return the unknown image if anonymous parameter is true if not it returns an empty array
2205
     */
2206
    public static function getUserPicturePathById($id, $type = 'web', $userInfo = [])
2207
    {
2208
        switch ($type) {
2209
            case 'system': // Base: absolute system path.
2210
                $base = api_get_path(SYS_CODE_PATH);
2211
                break;
2212
            case 'web': // Base: absolute web path.
2213
            default:
2214
                $base = api_get_path(WEB_CODE_PATH);
2215
                break;
2216
        }
2217
2218
        $anonymousPath = [
2219
            'dir' => $base.'img/',
2220
            'file' => 'unknown.jpg',
2221
            'email' => '',
2222
        ];
2223
2224
        if (empty($id) || empty($type)) {
2225
            return $anonymousPath;
2226
        }
2227
2228
        $id = (int) $id;
2229
        if (empty($userInfo)) {
2230
            $user_table = Database::get_main_table(TABLE_MAIN_USER);
2231
            $sql = "SELECT email, picture_uri FROM $user_table WHERE id = $id";
2232
            $res = Database::query($sql);
2233
2234
            if (!Database::num_rows($res)) {
2235
                return $anonymousPath;
2236
            }
2237
            $user = Database::fetch_array($res);
2238
2239
            if (empty($user['picture_uri'])) {
2240
                return $anonymousPath;
2241
            }
2242
        } else {
2243
            $user = $userInfo;
2244
        }
2245
2246
        $pictureFilename = trim($user['picture_uri']);
2247
        $dir = self::getUserPathById($id, $type);
2248
2249
        return [
2250
            'dir' => $dir,
2251
            'file' => $pictureFilename,
2252
            'email' => $user['email'],
2253
        ];
2254
    }
2255
2256
    /**
2257
     * Get user path from user ID (returns an array).
2258
     * The return format is a complete path to a folder ending with "/"
2259
     * In case the first level of subdirectory of users/ does not exist, the
2260
     * function will attempt to create it. Probably not the right place to do it
2261
     * but at least it avoids headaches in many other places.
2262
     *
2263
     * @param int    $id   User ID
2264
     * @param string $type Type of path to return (can be 'system', 'web', 'last')
2265
     *
2266
     * @return string User folder path (i.e. /var/www/chamilo/app/upload/users/1/1/)
2267
     */
2268
    public static function getUserPathById($id, $type)
2269
    {
2270
        $id = (int) $id;
2271
        if (!$id) {
2272
            return null;
2273
        }
2274
2275
        $userPath = "users/$id/";
2276
        if (api_get_setting('split_users_upload_directory') === 'true') {
2277
            $userPath = 'users/'.substr((string) $id, 0, 1).'/'.$id.'/';
2278
            // In exceptional cases, on some portals, the intermediate base user
2279
            // directory might not have been created. Make sure it is before
2280
            // going further.
2281
2282
            $rootPath = api_get_path(SYS_UPLOAD_PATH).'users/'.substr((string) $id, 0, 1);
2283
            if (!is_dir($rootPath)) {
2284
                $perm = api_get_permissions_for_new_directories();
2285
                try {
2286
                    mkdir($rootPath, $perm);
2287
                } catch (Exception $e) {
2288
                    error_log($e->getMessage());
2289
                }
2290
            }
2291
        }
2292
        switch ($type) {
2293
            case 'system': // Base: absolute system path.
2294
                $userPath = api_get_path(SYS_UPLOAD_PATH).$userPath;
2295
                break;
2296
            case 'web': // Base: absolute web path.
2297
                $userPath = api_get_path(WEB_UPLOAD_PATH).$userPath;
2298
                break;
2299
            case 'last': // Only the last part starting with users/
2300
                break;
2301
        }
2302
2303
        return $userPath;
2304
    }
2305
2306
    /**
2307
     * Gets the current user image.
2308
     *
2309
     * @param string $user_id
2310
     * @param int    $size        it can be USER_IMAGE_SIZE_SMALL,
2311
     *                            USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
2312
     * @param bool   $addRandomId
2313
     * @param array  $userInfo    to avoid query the DB
2314
     *
2315
     * @return string
2316
     */
2317
    public static function getUserPicture(
2318
        $user_id,
2319
        $size = USER_IMAGE_SIZE_MEDIUM,
2320
        $addRandomId = true,
2321
        $userInfo = []
2322
    ) {
2323
        // Make sure userInfo is defined. Otherwise, define it!
2324
        if (empty($userInfo) || !is_array($userInfo) || count($userInfo) == 0) {
2325
            if (empty($user_id)) {
2326
                return '';
2327
            } else {
2328
                $userInfo = api_get_user_info($user_id);
2329
            }
2330
        }
2331
2332
        $imageWebPath = self::get_user_picture_path_by_id(
2333
            $user_id,
2334
            'web',
2335
            $userInfo
2336
        );
2337
        $pictureWebFile = $imageWebPath['file'];
2338
        $pictureWebDir = $imageWebPath['dir'];
2339
2340
        $pictureAnonymousSize = '128';
2341
        $gravatarSize = 22;
2342
        $realSizeName = 'small_';
2343
2344
        switch ($size) {
2345
            case USER_IMAGE_SIZE_SMALL:
2346
                $pictureAnonymousSize = '32';
2347
                $realSizeName = 'small_';
2348
                $gravatarSize = 32;
2349
                break;
2350
            case USER_IMAGE_SIZE_MEDIUM:
2351
                $pictureAnonymousSize = '64';
2352
                $realSizeName = 'medium_';
2353
                $gravatarSize = 64;
2354
                break;
2355
            case USER_IMAGE_SIZE_ORIGINAL:
2356
                $pictureAnonymousSize = '128';
2357
                $realSizeName = '';
2358
                $gravatarSize = 128;
2359
                break;
2360
            case USER_IMAGE_SIZE_BIG:
2361
                $pictureAnonymousSize = '128';
2362
                $realSizeName = 'big_';
2363
                $gravatarSize = 128;
2364
                break;
2365
        }
2366
2367
        $gravatarEnabled = api_get_setting('gravatar_enabled');
2368
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
2369
        if ($pictureWebFile == 'unknown.jpg' || empty($pictureWebFile)) {
2370
            if ($gravatarEnabled === 'true') {
2371
                $file = self::getGravatar(
2372
                    $imageWebPath['email'],
2373
                    $gravatarSize,
2374
                    api_get_setting('gravatar_type')
2375
                );
2376
2377
                if ($addRandomId) {
2378
                    $file .= '&rand='.uniqid();
2379
                }
2380
2381
                return $file;
2382
            }
2383
2384
            return $anonymousPath;
2385
        }
2386
2387
        $pictureSysPath = self::get_user_picture_path_by_id($user_id, 'system');
2388
        $file = $pictureSysPath['dir'].$realSizeName.$pictureWebFile;
2389
        $picture = '';
2390
        if (file_exists($file)) {
2391
            $picture = $pictureWebDir.$realSizeName.$pictureWebFile;
2392
        } else {
2393
            $file = $pictureSysPath['dir'].$pictureWebFile;
2394
            if (file_exists($file) && !is_dir($file)) {
2395
                $picture = $pictureWebFile['dir'].$pictureWebFile;
2396
            }
2397
        }
2398
2399
        if (empty($picture)) {
2400
            return $anonymousPath;
2401
        }
2402
2403
        if ($addRandomId) {
2404
            $picture .= '?rand='.uniqid();
2405
        }
2406
2407
        return $picture;
2408
    }
2409
2410
    /**
2411
     * Creates new user photos in various sizes of a user, or deletes user photos.
2412
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php.
2413
     *
2414
     * @param int    $user_id the user internal identification number
2415
     * @param string $file    The common file name for the newly created photos.
2416
     *                        It will be checked and modified for compatibility with the file system.
2417
     *                        If full name is provided, path component is ignored.
2418
     *                        If an empty name is provided, then old user photos are deleted only,
2419
     *
2420
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
2421
     *
2422
     * @param string $source_file    the full system name of the image from which user photos will be created
2423
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
2424
     *
2425
     * @return bool Returns the resulting common file name of created images which usually should be stored in database.
2426
     *              When deletion is requested returns empty string.
2427
     *              In case of internal error or negative validation returns FALSE.
2428
     */
2429
    public static function update_user_picture(
2430
        $user_id,
2431
        $file = null,
2432
        $source_file = null,
2433
        $cropParameters = ''
2434
    ) {
2435
        if (empty($user_id)) {
2436
            return false;
2437
        }
2438
        $delete = empty($file);
2439
        if (empty($source_file)) {
2440
            $source_file = $file;
2441
        }
2442
2443
        // User-reserved directory where photos have to be placed.
2444
        $path_info = self::getUserPicturePathById($user_id, 'system');
2445
        $path = $path_info['dir'];
2446
2447
        // If this directory does not exist - we create it.
2448
        if (!file_exists($path)) {
2449
            mkdir($path, api_get_permissions_for_new_directories(), true);
2450
        }
2451
2452
        // The old photos (if any).
2453
        $old_file = $path_info['file'];
2454
2455
        // Let us delete them.
2456
        if ($old_file != 'unknown.jpg') {
2457
            if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE) {
0 ignored issues
show
Bug introduced by
The constant KEEP_THE_OLD_IMAGE_AFTER_CHANGE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2458
                $prefix = 'saved_'.date('Y_m_d_H_i_s').'_'.uniqid('').'_';
2459
                @rename($path.'small_'.$old_file, $path.$prefix.'small_'.$old_file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

2459
                /** @scrutinizer ignore-unhandled */ @rename($path.'small_'.$old_file, $path.$prefix.'small_'.$old_file);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2460
                @rename($path.'medium_'.$old_file, $path.$prefix.'medium_'.$old_file);
2461
                @rename($path.'big_'.$old_file, $path.$prefix.'big_'.$old_file);
2462
                @rename($path.$old_file, $path.$prefix.$old_file);
2463
            } else {
2464
                @unlink($path.'small_'.$old_file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

2464
                /** @scrutinizer ignore-unhandled */ @unlink($path.'small_'.$old_file);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2465
                @unlink($path.'medium_'.$old_file);
2466
                @unlink($path.'big_'.$old_file);
2467
                @unlink($path.$old_file);
2468
            }
2469
        }
2470
2471
        // Exit if only deletion has been requested. Return an empty picture name.
2472
        if ($delete) {
2473
            return '';
2474
        }
2475
2476
        // Validation 2.
2477
        $allowed_types = api_get_supported_image_extensions();
2478
        $file = str_replace('\\', '/', $file);
2479
        $filename = (($pos = strrpos($file, '/')) !== false) ? substr($file, $pos + 1) : $file;
2480
        $extension = strtolower(substr(strrchr($filename, '.'), 1));
2481
        if (!in_array($extension, $allowed_types)) {
2482
            return false;
2483
        }
2484
2485
        // This is the common name for the new photos.
2486
        if (KEEP_THE_NAME_WHEN_CHANGE_IMAGE && $old_file != 'unknown.jpg') {
0 ignored issues
show
Bug introduced by
The constant KEEP_THE_NAME_WHEN_CHANGE_IMAGE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2487
            $old_extension = strtolower(substr(strrchr($old_file, '.'), 1));
2488
            $filename = in_array($old_extension, $allowed_types) ? substr($old_file, 0, -strlen($old_extension)) : $old_file;
2489
            $filename = (substr($filename, -1) == '.') ? $filename.$extension : $filename.'.'.$extension;
2490
        } else {
2491
            $filename = api_replace_dangerous_char($filename);
2492
            if (PREFIX_IMAGE_FILENAME_WITH_UID) {
0 ignored issues
show
Bug introduced by
The constant PREFIX_IMAGE_FILENAME_WITH_UID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2493
                $filename = uniqid('').'_'.$filename;
2494
            }
2495
            // We always prefix user photos with user ids, so on setting
2496
            // api_get_setting('split_users_upload_directory') === 'true'
2497
            // the correspondent directories to be found successfully.
2498
            $filename = $user_id.'_'.$filename;
2499
        }
2500
2501
        //Crop the image to adjust 1:1 ratio
2502
        $image = new Image($source_file);
2503
        $image->crop($cropParameters);
2504
2505
        // Storing the new photos in 4 versions with various sizes.
2506
        $userPath = self::getUserPathById($user_id, 'system');
2507
2508
        // If this path does not exist - we create it.
2509
        if (!file_exists($userPath)) {
2510
            mkdir($userPath, api_get_permissions_for_new_directories(), true);
2511
        }
2512
        $small = new Image($source_file);
2513
        $small->resize(32);
2514
        $small->send_image($userPath.'small_'.$filename);
2515
        $medium = new Image($source_file);
2516
        $medium->resize(85);
2517
        $medium->send_image($userPath.'medium_'.$filename);
2518
        $normal = new Image($source_file);
2519
        $normal->resize(200);
2520
        $normal->send_image($userPath.$filename);
2521
2522
        $big = new Image($source_file); // This is the original picture.
2523
        $big->send_image($userPath.'big_'.$filename);
2524
2525
        $result = $small && $medium && $normal && $big;
0 ignored issues
show
introduced by
$big is of type Image, thus it always evaluated to true.
Loading history...
introduced by
$medium is of type Image, thus it always evaluated to true.
Loading history...
introduced by
$normal is of type Image, thus it always evaluated to true.
Loading history...
2526
2527
        return $result ? $filename : false;
2528
    }
2529
2530
    /**
2531
     * Update User extra field file type into {user_folder}/{$extra_field}.
2532
     *
2533
     * @param int    $user_id     The user internal identification number
2534
     * @param string $extra_field The $extra_field The extra field name
2535
     * @param null   $file        The filename
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $file is correct as it would always require null to be passed?
Loading history...
2536
     * @param null   $source_file The temporal filename
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $source_file is correct as it would always require null to be passed?
Loading history...
2537
     *
2538
     * @return bool|null return filename if success, but false
2539
     */
2540
    public static function update_user_extra_file(
2541
        $user_id,
2542
        $extra_field = '',
2543
        $file = null,
2544
        $source_file = null
2545
    ) {
2546
        // Add Filter
2547
        $source_file = Security::filter_filename($source_file);
2548
        $file = Security::filter_filename($file);
2549
2550
        if (empty($user_id)) {
2551
            return false;
2552
        }
2553
2554
        if (empty($source_file)) {
2555
            $source_file = $file;
2556
        }
2557
2558
        // User-reserved directory where extra file have to be placed.
2559
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2560
        $path = $path_info['dir'];
2561
        if (!empty($extra_field)) {
2562
            $path .= $extra_field.'/';
2563
        }
2564
        // If this directory does not exist - we create it.
2565
        if (!file_exists($path)) {
2566
            @mkdir($path, api_get_permissions_for_new_directories(), true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

2566
            /** @scrutinizer ignore-unhandled */ @mkdir($path, api_get_permissions_for_new_directories(), true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2567
        }
2568
2569
        if (filter_extension($file)) {
2570
            if (@move_uploaded_file($source_file, $path.$file)) {
2571
                if ($extra_field) {
2572
                    return $extra_field.'/'.$file;
2573
                } else {
2574
                    return $file;
2575
                }
2576
            }
2577
        }
2578
2579
        return false; // this should be returned if anything went wrong with the upload
2580
    }
2581
2582
    /**
2583
     * Deletes user photos.
2584
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php.
2585
     *
2586
     * @param int $userId the user internal identification number
2587
     *
2588
     * @return mixed returns empty string on success, FALSE on error
2589
     */
2590
    public static function deleteUserPicture($userId)
2591
    {
2592
        return self::update_user_picture($userId);
2593
    }
2594
2595
    /**
2596
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
2597
     * doesn't have any.
2598
     *
2599
     * If there has been a request to remove a production, the function will return
2600
     * without building the list unless forced to do so by the optional second
2601
     * parameter. This increases performance by avoiding to read through the
2602
     * productions on the filesystem before the removal request has been carried
2603
     * out because they'll have to be re-read afterwards anyway.
2604
     *
2605
     * @param int  $user_id    User id
2606
     * @param bool $force      Optional parameter to force building after a removal request
2607
     * @param bool $showDelete
2608
     *
2609
     * @return string A string containing the XHTML code to display the production list, or FALSE
2610
     */
2611
    public static function build_production_list($user_id, $force = false, $showDelete = false)
2612
    {
2613
        if (!$force && !empty($_POST['remove_production'])) {
2614
            return true; // postpone reading from the filesystem
2615
        }
2616
2617
        $productions = self::get_user_productions($user_id);
2618
2619
        if (empty($productions)) {
2620
            return false;
2621
        }
2622
2623
        $production_dir = self::getUserPathById($user_id, 'web');
2624
        $del_image = Display::returnIconPath('delete.png');
2625
        $add_image = Display::returnIconPath('archive.png');
2626
        $del_text = get_lang('Delete');
2627
        $production_list = '';
2628
        if (count($productions) > 0) {
2629
            $production_list = '<div class="files-production"><ul id="productions">';
2630
            foreach ($productions as $file) {
2631
                $production_list .= '<li>
2632
                    <img src="'.$add_image.'" />
2633
                    <a href="'.$production_dir.urlencode($file).'" target="_blank">
2634
                        '.htmlentities($file).'
2635
                    </a>';
2636
                if ($showDelete) {
2637
                    $production_list .= '&nbsp;&nbsp;
2638
                        <input
2639
                            style="width:16px;"
2640
                            type="image"
2641
                            name="remove_production['.urlencode($file).']"
2642
                            src="'.$del_image.'"
2643
                            alt="'.$del_text.'"
2644
                            title="'.$del_text.' '.htmlentities($file).'"
2645
                            onclick="javascript: return confirmation(\''.htmlentities($file).'\');" /></li>';
2646
                }
2647
            }
2648
            $production_list .= '</ul></div>';
2649
        }
2650
2651
        return $production_list;
2652
    }
2653
2654
    /**
2655
     * Returns an array with the user's productions.
2656
     *
2657
     * @param int $user_id User id
2658
     *
2659
     * @return array An array containing the user's productions
2660
     */
2661
    public static function get_user_productions($user_id)
2662
    {
2663
        $production_repository = self::getUserPathById($user_id, 'system');
2664
        $productions = [];
2665
2666
        if (is_dir($production_repository)) {
2667
            $handle = opendir($production_repository);
2668
            while ($file = readdir($handle)) {
2669
                if ($file == '.' ||
2670
                    $file == '..' ||
2671
                    $file == '.htaccess' ||
2672
                    is_dir($production_repository.$file)
2673
                ) {
2674
                    // skip current/parent directory and .htaccess
2675
                    continue;
2676
                }
2677
2678
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
2679
                    // User's photos should not be listed as productions.
2680
                    continue;
2681
                }
2682
                $productions[] = $file;
2683
            }
2684
        }
2685
2686
        return $productions;
2687
    }
2688
2689
    /**
2690
     * Remove a user production.
2691
     *
2692
     * @param int    $user_id    User id
2693
     * @param string $production The production to remove
2694
     *
2695
     * @return bool
2696
     */
2697
    public static function remove_user_production($user_id, $production)
2698
    {
2699
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
2700
        $production_file = $production_path['dir'].$production;
2701
        if (is_file($production_file)) {
2702
            unlink($production_file);
2703
2704
            return true;
2705
        }
2706
2707
        return false;
2708
    }
2709
2710
    /**
2711
     * Update an extra field value for a given user.
2712
     *
2713
     * @param int    $userId   User ID
2714
     * @param string $variable Field variable name
2715
     * @param string $value    Field value
2716
     *
2717
     * @return bool true if field updated, false otherwise
2718
     */
2719
    public static function update_extra_field_value($userId, $variable, $value = '')
2720
    {
2721
        $extraFieldValue = new ExtraFieldValue('user');
2722
        $params = [
2723
            'item_id' => $userId,
2724
            'variable' => $variable,
2725
            'value' => $value,
2726
        ];
2727
2728
        return $extraFieldValue->save($params);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraFieldValue->save($params) also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
2729
    }
2730
2731
    /**
2732
     * Get an array of extra fields with field details (type, default value and options).
2733
     *
2734
     * @param    int    Offset (from which row)
2735
     * @param    int    Number of items
2736
     * @param    int    Column on which sorting is made
2737
     * @param    string    Sorting direction
2738
     * @param    bool    Optional. Whether we get all the fields or just the visible ones
0 ignored issues
show
Documentation Bug introduced by
The doc comment Optional. at position 0 could not be parsed: Unknown type name 'Optional.' at position 0 in Optional..
Loading history...
2739
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
2740
     *
2741
     * @return array Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
2742
     */
2743
    public static function get_extra_fields(
2744
        $from = 0,
2745
        $number_of_items = 0,
2746
        $column = 5,
2747
        $direction = 'ASC',
2748
        $all_visibility = true,
2749
        $field_filter = null
2750
    ) {
2751
        $fields = [];
2752
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2753
        $t_ufo = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
2754
        $columns = [
2755
            'id',
2756
            'variable',
2757
            'field_type',
2758
            'display_text',
2759
            'default_value',
2760
            'field_order',
2761
            'filter',
2762
        ];
2763
        $column = (int) $column;
2764
        $sort_direction = '';
2765
        if (in_array(strtoupper($direction), ['ASC', 'DESC'])) {
2766
            $sort_direction = strtoupper($direction);
2767
        }
2768
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
2769
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
2770
        if (!$all_visibility) {
2771
            $sqlf .= " AND visible_to_self = 1 ";
2772
        }
2773
        if (!is_null($field_filter)) {
2774
            $field_filter = (int) $field_filter;
2775
            $sqlf .= " AND filter = $field_filter ";
2776
        }
2777
        $sqlf .= " ORDER BY ".$columns[$column]." $sort_direction ";
2778
        if ($number_of_items != 0) {
2779
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
2780
        }
2781
        $resf = Database::query($sqlf);
2782
        if (Database::num_rows($resf) > 0) {
2783
            while ($rowf = Database::fetch_array($resf)) {
2784
                $fields[$rowf['id']] = [
2785
                    0 => $rowf['id'],
2786
                    1 => $rowf['variable'],
2787
                    2 => $rowf['field_type'],
2788
                    3 => empty($rowf['display_text']) ? '' : $rowf['display_text'],
2789
                    4 => $rowf['default_value'],
2790
                    5 => $rowf['field_order'],
2791
                    6 => $rowf['visible_to_self'],
2792
                    7 => $rowf['changeable'],
2793
                    8 => $rowf['filter'],
2794
                    9 => [],
2795
                    10 => '<a name="'.$rowf['id'].'"></a>',
2796
                ];
2797
2798
                $sqlo = "SELECT * FROM $t_ufo
2799
                         WHERE field_id = ".$rowf['id']."
2800
                         ORDER BY option_order ASC";
2801
                $reso = Database::query($sqlo);
2802
                if (Database::num_rows($reso) > 0) {
2803
                    while ($rowo = Database::fetch_array($reso)) {
2804
                        $fields[$rowf['id']][9][$rowo['id']] = [
2805
                            0 => $rowo['id'],
2806
                            1 => $rowo['option_value'],
2807
                            2 => empty($rowo['display_text']) ? '' : $rowo['display_text'],
2808
                            3 => $rowo['option_order'],
2809
                        ];
2810
                    }
2811
                }
2812
            }
2813
        }
2814
2815
        return $fields;
2816
    }
2817
2818
    /**
2819
     * Build a list of extra file already uploaded in $user_folder/{$extra_field}/.
2820
     *
2821
     * @param $user_id
2822
     * @param $extra_field
2823
     * @param bool $force
2824
     * @param bool $showDelete
2825
     *
2826
     * @return bool|string
2827
     */
2828
    public static function build_user_extra_file_list(
2829
        $user_id,
2830
        $extra_field,
2831
        $force = false,
2832
        $showDelete = false
2833
    ) {
2834
        if (!$force && !empty($_POST['remove_'.$extra_field])) {
2835
            return true; // postpone reading from the filesystem
2836
        }
2837
2838
        $extra_files = self::get_user_extra_files($user_id, $extra_field);
2839
        if (empty($extra_files)) {
2840
            return false;
2841
        }
2842
2843
        $path_info = self::get_user_picture_path_by_id($user_id, 'web');
2844
        $path = $path_info['dir'];
2845
        $del_image = Display::returnIconPath('delete.png');
2846
2847
        $del_text = get_lang('Delete');
2848
        $extra_file_list = '';
2849
        if (count($extra_files) > 0) {
2850
            $extra_file_list = '<div class="files-production"><ul id="productions">';
2851
            foreach ($extra_files as $file) {
2852
                $filename = substr($file, strlen($extra_field) + 1);
2853
                $extra_file_list .= '<li>'.Display::return_icon('archive.png').
2854
                    '<a href="'.$path.$extra_field.'/'.urlencode($filename).'" target="_blank">
2855
                        '.htmlentities($filename).
2856
                    '</a> ';
2857
                if ($showDelete) {
2858
                    $extra_file_list .= '<input
2859
                        style="width:16px;"
2860
                        type="image"
2861
                        name="remove_extra_'.$extra_field.'['.urlencode($file).']"
2862
                        src="'.$del_image.'"
2863
                        alt="'.$del_text.'"
2864
                        title="'.$del_text.' '.htmlentities($filename).'"
2865
                        onclick="javascript: return confirmation(\''.htmlentities($filename).'\');" /></li>';
2866
                }
2867
            }
2868
            $extra_file_list .= '</ul></div>';
2869
        }
2870
2871
        return $extra_file_list;
2872
    }
2873
2874
    /**
2875
     * Get valid filenames in $user_folder/{$extra_field}/.
2876
     *
2877
     * @param $user_id
2878
     * @param $extra_field
2879
     * @param bool $full_path
2880
     *
2881
     * @return array
2882
     */
2883
    public static function get_user_extra_files($user_id, $extra_field, $full_path = false)
2884
    {
2885
        if (!$full_path) {
2886
            // Nothing to do
2887
        } else {
2888
            $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2889
            $path = $path_info['dir'];
2890
        }
2891
        $extra_data = self::get_extra_user_data_by_field($user_id, $extra_field);
2892
        $extra_files = $extra_data[$extra_field];
2893
2894
        $files = [];
2895
        if (is_array($extra_files)) {
2896
            foreach ($extra_files as $key => $value) {
2897
                if (!$full_path) {
2898
                    // Relative path from user folder
2899
                    $files[] = $value;
2900
                } else {
2901
                    $files[] = $path.$value;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $path does not seem to be defined for all execution paths leading up to this point.
Loading history...
2902
                }
2903
            }
2904
        } elseif (!empty($extra_files)) {
2905
            if (!$full_path) {
2906
                // Relative path from user folder
2907
                $files[] = $extra_files;
2908
            } else {
2909
                $files[] = $path.$extra_files;
2910
            }
2911
        }
2912
2913
        return $files; // can be an empty array
2914
    }
2915
2916
    /**
2917
     * Remove an {$extra_file} from the user folder $user_folder/{$extra_field}/.
2918
     *
2919
     * @param int    $user_id
2920
     * @param string $extra_field
2921
     * @param string $extra_file
2922
     *
2923
     * @return bool
2924
     */
2925
    public static function remove_user_extra_file($user_id, $extra_field, $extra_file)
2926
    {
2927
        $extra_file = Security::filter_filename($extra_file);
2928
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2929
        if (strpos($extra_file, $extra_field) !== false) {
2930
            $path_extra_file = $path_info['dir'].$extra_file;
2931
        } else {
2932
            $path_extra_file = $path_info['dir'].$extra_field.'/'.$extra_file;
2933
        }
2934
        if (is_file($path_extra_file)) {
2935
            unlink($path_extra_file);
2936
2937
            return true;
2938
        }
2939
2940
        return false;
2941
    }
2942
2943
    /**
2944
     * Creates a new extra field.
2945
     *
2946
     * @param string $variable    Field's internal variable name
2947
     * @param int    $fieldType   Field's type
2948
     * @param string $displayText Field's language var name
2949
     * @param string $default     Field's default value
2950
     *
2951
     * @return int
2952
     */
2953
    public static function create_extra_field(
2954
        $variable,
2955
        $fieldType,
2956
        $displayText,
2957
        $default
2958
    ) {
2959
        $extraField = new ExtraField('user');
2960
        $params = [
2961
            'variable' => $variable,
2962
            'field_type' => $fieldType,
2963
            'display_text' => $displayText,
2964
            'default_value' => $default,
2965
        ];
2966
2967
        return $extraField->save($params);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->save($params) also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
2968
    }
2969
2970
    /**
2971
     * Check if a field is available.
2972
     *
2973
     * @param string $variable
2974
     *
2975
     * @return bool
2976
     */
2977
    public static function is_extra_field_available($variable)
2978
    {
2979
        $extraField = new ExtraField('user');
2980
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2981
2982
        return !empty($data) ? true : false;
2983
    }
2984
2985
    /**
2986
     * Gets user extra fields data.
2987
     *
2988
     * @param    int    User ID
2989
     * @param    bool    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2990
     * @param    bool    Whether to return invisible fields as well
2991
     * @param    bool    Whether to split multiple-selection fields or not
2992
     *
2993
     * @return array Array of fields => value for the given user
2994
     */
2995
    public static function get_extra_user_data(
2996
        $user_id,
2997
        $prefix = false,
2998
        $allVisibility = true,
2999
        $splitMultiple = false,
3000
        $fieldFilter = null
3001
    ) {
3002
        $user_id = (int) $user_id;
3003
3004
        if (empty($user_id)) {
3005
            return [];
3006
        }
3007
3008
        $extra_data = [];
3009
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
3010
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
3011
        $user_id = (int) $user_id;
3012
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
3013
                FROM $t_uf f
3014
                WHERE
3015
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
3016
                ";
3017
        $filter_cond = '';
3018
3019
        if (!$allVisibility) {
3020
            if (isset($fieldFilter)) {
3021
                $fieldFilter = (int) $fieldFilter;
3022
                $filter_cond .= " AND filter = $fieldFilter ";
3023
            }
3024
            $sql .= " AND f.visible_to_self = 1 $filter_cond ";
3025
        } else {
3026
            if (isset($fieldFilter)) {
3027
                $fieldFilter = (int) $fieldFilter;
3028
                $sql .= " AND filter = $fieldFilter ";
3029
            }
3030
        }
3031
3032
        $sql .= ' ORDER BY f.field_order';
3033
3034
        $res = Database::query($sql);
3035
        if (Database::num_rows($res) > 0) {
3036
            while ($row = Database::fetch_array($res)) {
3037
                if ($row['type'] == self::USER_FIELD_TYPE_TAG) {
3038
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
3039
                    $extra_data['extra_'.$row['fvar']] = $tags;
3040
                } else {
3041
                    $sqlu = "SELECT value as fval
3042
                            FROM $t_ufv
3043
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
3044
                    $resu = Database::query($sqlu);
3045
                    // get default value
3046
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
3047
                               WHERE id=".$row['id'];
3048
                    $res_df = Database::query($sql_df);
3049
3050
                    if (Database::num_rows($resu) > 0) {
3051
                        $rowu = Database::fetch_array($resu);
3052
                        $fval = $rowu['fval'];
3053
                        if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
3054
                            $fval = explode(';', $rowu['fval']);
3055
                        }
3056
                    } else {
3057
                        $row_df = Database::fetch_array($res_df);
3058
                        $fval = $row_df['fval_df'];
3059
                    }
3060
                    // We get here (and fill the $extra_data array) even if there
3061
                    // is no user with data (we fill it with default values)
3062
                    if ($prefix) {
3063
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
3064
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
3065
                        } else {
3066
                            $extra_data['extra_'.$row['fvar']] = $fval;
3067
                        }
3068
                    } else {
3069
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
3070
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
3071
                        } else {
3072
                            $extra_data[$row['fvar']] = $fval;
3073
                        }
3074
                    }
3075
                }
3076
            }
3077
        }
3078
3079
        return $extra_data;
3080
    }
3081
3082
    /**
3083
     * Get extra user data by field.
3084
     *
3085
     * @param int    user ID
3086
     * @param string the internal variable name of the field
3087
     *
3088
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
3089
     */
3090
    public static function get_extra_user_data_by_field(
3091
        $user_id,
3092
        $field_variable,
3093
        $prefix = false,
3094
        $all_visibility = true,
3095
        $splitmultiple = false
3096
    ) {
3097
        $user_id = (int) $user_id;
3098
3099
        if (empty($user_id)) {
3100
            return [];
3101
        }
3102
3103
        $extra_data = [];
3104
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
3105
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
3106
3107
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
3108
                FROM $t_uf f
3109
                WHERE f.variable = '$field_variable' ";
3110
3111
        if (!$all_visibility) {
3112
            $sql .= " AND f.visible_to_self = 1 ";
3113
        }
3114
3115
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
3116
        $sql .= " ORDER BY f.field_order ";
3117
3118
        $res = Database::query($sql);
3119
        if (Database::num_rows($res) > 0) {
3120
            while ($row = Database::fetch_array($res)) {
3121
                $sqlu = "SELECT value as fval FROM $t_ufv v
3122
                         INNER JOIN $t_uf f
3123
                         ON (v.field_id = f.id)
3124
                         WHERE
3125
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
3126
                            field_id = ".$row['id']." AND
3127
                            item_id = ".$user_id;
3128
                $resu = Database::query($sqlu);
3129
                $fval = '';
3130
                if (Database::num_rows($resu) > 0) {
3131
                    $rowu = Database::fetch_array($resu);
3132
                    $fval = $rowu['fval'];
3133
                    if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
3134
                        $fval = explode(';', $rowu['fval']);
3135
                    }
3136
                }
3137
                if ($prefix) {
3138
                    $extra_data['extra_'.$row['fvar']] = $fval;
3139
                } else {
3140
                    $extra_data[$row['fvar']] = $fval;
3141
                }
3142
            }
3143
        }
3144
3145
        return $extra_data;
3146
    }
3147
3148
    /**
3149
     * Get the extra field information for a certain field (the options as well).
3150
     *
3151
     * @param string $variable The name of the field we want to know everything about
3152
     *
3153
     * @return array Array containing all the information about the extra profile field
3154
     *               (first level of array contains field details, then 'options' sub-array contains options details,
3155
     *               as returned by the database)
3156
     *
3157
     * @author Julio Montoya
3158
     *
3159
     * @since v1.8.6
3160
     */
3161
    public static function get_extra_field_information_by_name($variable)
3162
    {
3163
        $extraField = new ExtraField('user');
3164
3165
        return $extraField->get_handler_field_info_by_field_variable($variable);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->get_...eld_variable($variable) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
3166
    }
3167
3168
    /**
3169
     * Get the extra field information for user tag (the options as well).
3170
     *
3171
     * @param int $variable The name of the field we want to know everything about
3172
     *
3173
     * @return array Array containing all the information about the extra profile field
3174
     *               (first level of array contains field details, then 'options' sub-array contains options details,
3175
     *               as returned by the database)
3176
     *
3177
     * @author José Loguercio
3178
     *
3179
     * @since v1.11.0
3180
     */
3181
    public static function get_extra_field_tags_information_by_name($variable)
3182
    {
3183
        $extraField = new ExtraField('user');
3184
3185
        return $extraField->get_handler_field_info_by_tags($variable);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->get_...info_by_tags($variable) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
3186
    }
3187
3188
    /**
3189
     * @param string $type
3190
     *
3191
     * @return array
3192
     */
3193
    public static function get_all_extra_field_by_type($type)
3194
    {
3195
        $extraField = new ExtraField('user');
3196
3197
        return $extraField->get_all_extra_field_by_type($type);
3198
    }
3199
3200
    /**
3201
     * Get all the extra field information of a certain field (also the options).
3202
     *
3203
     * @param int $fieldId the ID of the field we want to know everything of
3204
     *
3205
     * @return array $return containing all th information about the extra profile field
3206
     *
3207
     * @author Julio Montoya
3208
     *
3209
     * @deprecated
3210
     * @since v1.8.6
3211
     */
3212
    public static function get_extra_field_information($fieldId)
3213
    {
3214
        $extraField = new ExtraField('user');
3215
3216
        return $extraField->getFieldInfoByFieldId($fieldId);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->getF...InfoByFieldId($fieldId) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
3217
    }
3218
3219
    /**
3220
     * Get extra user data by value.
3221
     *
3222
     * @param string $variable the internal variable name of the field
3223
     * @param string $value    the internal value of the field
3224
     * @param bool   $useLike
3225
     *
3226
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
3227
     */
3228
    public static function get_extra_user_data_by_value($variable, $value, $useLike = false)
3229
    {
3230
        $extraFieldValue = new ExtraFieldValue('user');
3231
        $extraField = new ExtraField('user');
3232
3233
        $info = $extraField->get_handler_field_info_by_field_variable($variable);
3234
3235
        if (false === $info) {
3236
            return [];
3237
        }
3238
3239
        $data = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
3240
            $variable,
3241
            $value,
3242
            false,
3243
            false,
3244
            true,
3245
            $useLike
3246
        );
3247
3248
        $result = [];
3249
        if (!empty($data)) {
3250
            foreach ($data as $item) {
3251
                $result[] = $item['item_id'];
3252
            }
3253
        }
3254
3255
        return $result;
3256
    }
3257
3258
    /**
3259
     * Get extra user data by tags value.
3260
     *
3261
     * @param int    $fieldId the ID of the field we want to know everything of
3262
     * @param string $tag     the tag name for search
3263
     *
3264
     * @return array with extra data info of a user
3265
     *
3266
     * @author José Loguercio
3267
     *
3268
     * @since v1.11.0
3269
     */
3270
    public static function get_extra_user_data_by_tags($fieldId, $tag)
3271
    {
3272
        $extraField = new ExtraField('user');
3273
        $result = $extraField->getAllUserPerTag($fieldId, $tag);
3274
        $array = [];
3275
        foreach ($result as $index => $user) {
3276
            $array[] = $user['user_id'];
3277
        }
3278
3279
        return $array;
3280
    }
3281
3282
    /**
3283
     * Get extra user data by field variable.
3284
     *
3285
     * @param string $variable field variable
3286
     *
3287
     * @return array data
3288
     */
3289
    public static function get_extra_user_data_by_field_variable($variable)
3290
    {
3291
        $extraInfo = self::get_extra_field_information_by_name($variable);
3292
        $field_id = (int) $extraInfo['id'];
3293
3294
        $extraField = new ExtraFieldValue('user');
3295
        $data = $extraField->getValuesByFieldId($field_id);
3296
3297
        if (!empty($data)) {
3298
            foreach ($data as $row) {
3299
                $user_id = $row['item_id'];
3300
                $data[$user_id] = $row;
3301
            }
3302
        }
3303
3304
        return $data;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $data could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
3305
    }
3306
3307
    /**
3308
     * Get extra user data tags by field variable.
3309
     *
3310
     * @param string $variable field variable
3311
     *
3312
     * @return array
3313
     */
3314
    public static function get_extra_user_data_for_tags($variable)
3315
    {
3316
        $data = self::get_extra_field_tags_information_by_name($variable);
3317
3318
        return $data;
3319
    }
3320
3321
    /**
3322
     * Gives a list of [session_category][session_id] for the current user.
3323
     *
3324
     * @param int  $user_id
3325
     * @param bool $is_time_over                 whether to fill the first element or not
3326
     *                                           (to give space for courses out of categories)
3327
     * @param bool $ignore_visibility_for_admins optional true if limit time from session is over, false otherwise
3328
     * @param bool $ignoreTimeLimit              ignore time start/end
3329
     * @param bool $getCount
3330
     *
3331
     * @return array list of statuses [session_category][session_id]
3332
     *
3333
     * @todo ensure multiple access urls are managed correctly
3334
     */
3335
    public static function get_sessions_by_category(
3336
        $user_id,
3337
        $is_time_over = true,
3338
        $ignore_visibility_for_admins = false,
3339
        $ignoreTimeLimit = false,
3340
        $getCount = false
3341
    ) {
3342
        $user_id = (int) $user_id;
3343
3344
        if (empty($user_id)) {
3345
            return [];
3346
        }
3347
3348
        $allowOrder = api_get_configuration_value('session_list_order');
3349
        $position = '';
3350
        if ($allowOrder) {
3351
            $position = ', s.position AS position ';
3352
        }
3353
3354
        // Get the list of sessions per user
3355
        $now = new DateTime('now', new DateTimeZone('UTC'));
3356
3357
        // LEFT JOIN is used for session_rel_course_rel_user because an inner
3358
        // join would not catch session-courses where the user is general
3359
        // session coach but which do not have students nor coaches registered
3360
        $dqlSelect = ' COUNT(DISTINCT s.id) ';
3361
3362
        if (!$getCount) {
3363
            $dqlSelect = " DISTINCT
3364
                s.id,
3365
                s.name,
3366
                s.accessStartDate AS access_start_date,
3367
                s.accessEndDate AS access_end_date,
3368
                s.duration,
3369
                sc.id AS session_category_id,
3370
                sc.name AS session_category_name,
3371
                sc.dateStart AS session_category_date_start,
3372
                sc.dateEnd AS session_category_date_end,
3373
                s.coachAccessStartDate AS coach_access_start_date,
3374
                s.coachAccessEndDate AS coach_access_end_date,
3375
                CASE WHEN s.accessEndDate IS NULL THEN 1 ELSE 0 END HIDDEN _isFieldNull
3376
                $position
3377
            ";
3378
        }
3379
3380
        $dql = "SELECT $dqlSelect
3381
                FROM ChamiloCoreBundle:Session AS s
3382
                LEFT JOIN ChamiloCoreBundle:SessionRelCourseRelUser AS scu WITH scu.session = s
3383
                INNER JOIN ChamiloCoreBundle:AccessUrlRelSession AS url WITH url.sessionId = s.id
3384
                LEFT JOIN ChamiloCoreBundle:SessionCategory AS sc WITH s.category = sc ";
3385
3386
        // A single OR operation on scu.user = :user OR s.generalCoach = :user
3387
        // is awfully inefficient for large sets of data (1m25s for 58K
3388
        // sessions, BT#14115) but executing a similar query twice and grouping
3389
        // the results afterwards in PHP takes about 1/1000th of the time
3390
        // (0.1s + 0.0s) for the same set of data, so we do it this way...
3391
        $dqlStudent = $dql.' WHERE scu.user = :user AND url.accessUrlId = :url ';
3392
        $dqlCoach = $dql.' WHERE s.generalCoach = :user AND url.accessUrlId = :url ';
3393
3394
        // Default order
3395
        $order = 'ORDER BY sc.name, s.name';
3396
3397
        // Order by date if showing all sessions
3398
        $showAllSessions = api_get_configuration_value('show_all_sessions_on_my_course_page') === true;
3399
        if ($showAllSessions) {
3400
            $order = 'ORDER BY s.accessStartDate';
3401
        }
3402
3403
        // Order by position
3404
        if ($allowOrder) {
3405
            $order = 'ORDER BY s.position';
3406
        }
3407
3408
        // Order by dates according to settings
3409
        $orderBySettings = api_get_configuration_value('my_courses_session_order');
3410
        if (!empty($orderBySettings) && isset($orderBySettings['field']) && isset($orderBySettings['order'])) {
3411
            $field = $orderBySettings['field'];
3412
            $orderSetting = $orderBySettings['order'];
3413
            switch ($field) {
3414
                case 'start_date':
3415
                    $order = " ORDER BY s.accessStartDate $orderSetting";
3416
                    break;
3417
                case 'end_date':
3418
                    $order = " ORDER BY s.accessEndDate $orderSetting ";
3419
                    if ($orderSetting === 'asc') {
3420
                        // Put null values at the end
3421
                        // https://stackoverflow.com/questions/12652034/how-can-i-order-by-null-in-dql
3422
                        $order = ' ORDER BY _isFieldNull asc, s.accessEndDate asc';
3423
                    }
3424
                    break;
3425
                case 'name':
3426
                    $order = " ORDER BY s.name $orderSetting ";
3427
                    break;
3428
            }
3429
        }
3430
3431
        $dqlStudent .= $order;
3432
        $dqlCoach .= $order;
3433
3434
        $accessUrlId = api_get_current_access_url_id();
3435
        $dqlStudent = Database::getManager()
3436
            ->createQuery($dqlStudent)
3437
            ->setParameters(
3438
                ['user' => $user_id, 'url' => $accessUrlId]
3439
            )
3440
        ;
3441
        $dqlCoach = Database::getManager()
3442
            ->createQuery($dqlCoach)
3443
            ->setParameters(
3444
                ['user' => $user_id, 'url' => $accessUrlId]
3445
            )
3446
        ;
3447
3448
        if ($getCount) {
3449
            return $dqlStudent->getSingleScalarResult() + $dqlCoach->getSingleScalarResult();
3450
        }
3451
3452
        $sessionDataStudent = $dqlStudent->getResult();
3453
        $sessionDataCoach = $dqlCoach->getResult();
3454
3455
        $sessionData = [];
3456
        // First fill $sessionData with student sessions
3457
        if (!empty($sessionDataStudent)) {
3458
            foreach ($sessionDataStudent as $row) {
3459
                $sessionData[$row['id']] = $row;
3460
            }
3461
        }
3462
3463
        // Overwrite session data of the user as a student with session data
3464
        // of the user as a coach.
3465
        // There shouldn't be such duplicate rows, but just in case...
3466
        if (!empty($sessionDataCoach)) {
3467
            foreach ($sessionDataCoach as $row) {
3468
                $sessionData[$row['id']] = $row;
3469
            }
3470
        }
3471
3472
        $collapsable = api_get_configuration_value('allow_user_session_collapsable');
3473
        $extraField = new ExtraFieldValue('session');
3474
        $collapsableLink = api_get_path(WEB_PATH).'user_portal.php?action=collapse_session';
3475
3476
        if (empty($sessionData)) {
3477
            return [];
3478
        }
3479
3480
        $categories = [];
3481
        foreach ($sessionData as $row) {
3482
            $session_id = $row['id'];
3483
            $coachList = SessionManager::getCoachesBySession($session_id);
3484
            $categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
3485
            $categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
3486
            $courseList = self::get_courses_list_by_session($user_id, $session_id);
3487
            $daysLeft = SessionManager::getDayLeftInSession($row, $user_id);
3488
3489
            // User portal filters:
3490
            if ($ignoreTimeLimit === false) {
3491
                if ($is_time_over) {
3492
                    // History
3493
                    if ($row['duration']) {
3494
                        if ($daysLeft >= 0) {
3495
                            continue;
3496
                        }
3497
                    } else {
3498
                        if (empty($row['access_end_date'])) {
3499
                            continue;
3500
                        } else {
3501
                            if ($row['access_end_date'] > $now) {
3502
                                continue;
3503
                            }
3504
                        }
3505
                    }
3506
                } else {
3507
                    // Current user portal
3508
                    $isGeneralCoach = SessionManager::user_is_general_coach($user_id, $row['id']);
3509
                    $isCoachOfCourse = in_array($user_id, $coachList);
3510
3511
                    if (api_is_platform_admin() || $isGeneralCoach || $isCoachOfCourse) {
3512
                        // Teachers can access the session depending in the access_coach date
3513
                    } else {
3514
                        if ($row['duration']) {
3515
                            if ($daysLeft <= 0) {
3516
                                continue;
3517
                            }
3518
                        } else {
3519
                            if (isset($row['access_end_date']) &&
3520
                                !empty($row['access_end_date'])
3521
                            ) {
3522
                                if ($row['access_end_date'] <= $now) {
3523
                                    continue;
3524
                                }
3525
                            }
3526
                        }
3527
                    }
3528
                }
3529
            }
3530
3531
            $categories[$row['session_category_id']]['session_category'] = [
3532
                'id' => $row['session_category_id'],
3533
                'name' => $row['session_category_name'],
3534
                'date_start' => $categoryStart,
3535
                'date_end' => $categoryEnd,
3536
            ];
3537
3538
            $visibility = api_get_session_visibility(
3539
                $session_id,
3540
                null,
3541
                $ignore_visibility_for_admins
3542
            );
3543
3544
            if ($visibility != SESSION_VISIBLE) {
3545
                // Course Coach session visibility.
3546
                $blockedCourseCount = 0;
3547
                $closedVisibilityList = [
3548
                    COURSE_VISIBILITY_CLOSED,
3549
                    COURSE_VISIBILITY_HIDDEN,
3550
                ];
3551
3552
                foreach ($courseList as $course) {
3553
                    // Checking session visibility
3554
                    $sessionCourseVisibility = api_get_session_visibility(
3555
                        $session_id,
3556
                        $course['real_id'],
3557
                        $ignore_visibility_for_admins
3558
                    );
3559
3560
                    $courseIsVisible = !in_array($course['visibility'], $closedVisibilityList);
3561
                    if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3562
                        $blockedCourseCount++;
3563
                    }
3564
                }
3565
3566
                // If all courses are blocked then no show in the list.
3567
                if ($blockedCourseCount === count($courseList)) {
3568
                    $visibility = SESSION_INVISIBLE;
3569
                } else {
3570
                    $visibility = $sessionCourseVisibility;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sessionCourseVisibility does not seem to be defined for all execution paths leading up to this point.
Loading history...
3571
                }
3572
            }
3573
3574
            switch ($visibility) {
3575
                case SESSION_VISIBLE_READ_ONLY:
3576
                case SESSION_VISIBLE:
3577
                case SESSION_AVAILABLE:
3578
                    break;
3579
                case SESSION_INVISIBLE:
3580
                    if ($ignore_visibility_for_admins === false) {
3581
                        continue 2;
3582
                    }
3583
            }
3584
3585
            $collapsed = '';
3586
            $collapsedAction = '';
3587
            if ($collapsable) {
3588
                $collapsableData = SessionManager::getCollapsableData(
3589
                    $user_id,
3590
                    $session_id,
3591
                    $extraField,
3592
                    $collapsableLink
3593
                );
3594
                $collapsed = $collapsableData['collapsed'];
3595
                $collapsedAction = $collapsableData['collapsable_link'];
3596
            }
3597
3598
            $categories[$row['session_category_id']]['sessions'][] = [
3599
                'session_name' => $row['name'],
3600
                'session_id' => $row['id'],
3601
                'access_start_date' => $row['access_start_date'] ? $row['access_start_date']->format('Y-m-d H:i:s') : null,
3602
                'access_end_date' => $row['access_end_date'] ? $row['access_end_date']->format('Y-m-d H:i:s') : null,
3603
                'coach_access_start_date' => $row['coach_access_start_date'] ? $row['coach_access_start_date']->format('Y-m-d H:i:s') : null,
3604
                'coach_access_end_date' => $row['coach_access_end_date'] ? $row['coach_access_end_date']->format('Y-m-d H:i:s') : null,
3605
                'courses' => $courseList,
3606
                'collapsed' => $collapsed,
3607
                'collapsable_link' => $collapsedAction,
3608
                'duration' => $row['duration'],
3609
            ];
3610
        }
3611
3612
        return $categories;
3613
    }
3614
3615
    /**
3616
     * Gives a list of [session_id-course_code] => [status] for the current user.
3617
     *
3618
     * @param int $user_id
3619
     * @param int $sessionLimit
3620
     *
3621
     * @return array list of statuses (session_id-course_code => status)
3622
     */
3623
    public static function get_personal_session_course_list($user_id, $sessionLimit = null)
3624
    {
3625
        // Database Table Definitions
3626
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3627
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
3628
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3629
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3630
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3631
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3632
3633
        $user_id = (int) $user_id;
3634
3635
        if (empty($user_id)) {
3636
            return [];
3637
        }
3638
3639
        // We filter the courses from the URL
3640
        $join_access_url = $where_access_url = '';
3641
        if (api_get_multiple_access_url()) {
3642
            $access_url_id = api_get_current_access_url_id();
3643
            if ($access_url_id != -1) {
3644
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3645
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
3646
                $where_access_url = " AND access_url_id = $access_url_id ";
3647
            }
3648
        }
3649
3650
        // Courses in which we subscribed out of any session
3651
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3652
3653
        $sql = "SELECT
3654
                    course.code,
3655
                    course_rel_user.status course_rel_status,
3656
                    course_rel_user.sort sort,
3657
                    course_rel_user.user_course_cat user_course_cat
3658
                 FROM $tbl_course_user course_rel_user
3659
                 LEFT JOIN $tbl_course course
3660
                 ON course.id = course_rel_user.c_id
3661
                 LEFT JOIN $tbl_user_course_category user_course_category
3662
                 ON course_rel_user.user_course_cat = user_course_category.id
3663
                 $join_access_url
3664
                 WHERE
3665
                    course_rel_user.user_id = '".$user_id."' AND
3666
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
3667
                    $where_access_url
3668
                 ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
3669
3670
        $course_list_sql_result = Database::query($sql);
3671
3672
        $personal_course_list = [];
3673
        if (Database::num_rows($course_list_sql_result) > 0) {
3674
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3675
                $course_info = api_get_course_info($result_row['code']);
3676
                $result_row['course_info'] = $course_info;
3677
                $personal_course_list[] = $result_row;
3678
            }
3679
        }
3680
3681
        $coachCourseConditions = '';
3682
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
3683
        if (api_is_allowed_to_create_course()) {
3684
            $sessionListFromCourseCoach = [];
3685
            $sql = " SELECT DISTINCT session_id
3686
                    FROM $tbl_session_course_user
3687
                    WHERE user_id = $user_id AND status = 2 ";
3688
3689
            $result = Database::query($sql);
3690
            if (Database::num_rows($result)) {
3691
                $result = Database::store_result($result);
3692
                foreach ($result as $session) {
3693
                    $sessionListFromCourseCoach[] = $session['session_id'];
3694
                }
3695
            }
3696
            if (!empty($sessionListFromCourseCoach)) {
3697
                $condition = implode("','", $sessionListFromCourseCoach);
3698
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
3699
            }
3700
        }
3701
3702
        // Get the list of sessions where the user is subscribed
3703
        // This is divided into two different queries
3704
        $sessions = [];
3705
        $sessionLimitRestriction = '';
3706
        if (!empty($sessionLimit)) {
3707
            $sessionLimit = (int) $sessionLimit;
3708
            $sessionLimitRestriction = "LIMIT $sessionLimit";
3709
        }
3710
3711
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3712
                FROM $tbl_session_user su INNER JOIN $tbl_session s
3713
                ON (s.id = su.session_id)
3714
                WHERE (
3715
                    su.user_id = $user_id AND
3716
                    su.relation_type <> ".SESSION_RELATION_TYPE_RRHH."
3717
                )
3718
                $coachCourseConditions
3719
                ORDER BY access_start_date, access_end_date, name
3720
                $sessionLimitRestriction
3721
        ";
3722
3723
        $result = Database::query($sql);
3724
        if (Database::num_rows($result) > 0) {
3725
            while ($row = Database::fetch_assoc($result)) {
3726
                $sessions[$row['id']] = $row;
3727
            }
3728
        }
3729
3730
        $sql = "SELECT DISTINCT
3731
                id, name, access_start_date, access_end_date
3732
                FROM $tbl_session s
3733
                WHERE (
3734
                    id_coach = $user_id
3735
                )
3736
                $coachCourseConditions
3737
                ORDER BY access_start_date, access_end_date, name";
3738
3739
        $result = Database::query($sql);
3740
        if (Database::num_rows($result) > 0) {
3741
            while ($row = Database::fetch_assoc($result)) {
3742
                if (empty($sessions[$row['id']])) {
3743
                    $sessions[$row['id']] = $row;
3744
                }
3745
            }
3746
        }
3747
3748
        if (api_is_allowed_to_create_course()) {
3749
            foreach ($sessions as $enreg) {
3750
                $session_id = $enreg['id'];
3751
                $session_visibility = api_get_session_visibility($session_id);
3752
3753
                if ($session_visibility == SESSION_INVISIBLE) {
3754
                    continue;
3755
                }
3756
3757
                // This query is horribly slow when more than a few thousand
3758
                // users and just a few sessions to which they are subscribed
3759
                $sql = "SELECT DISTINCT
3760
                        course.code code,
3761
                        course.title i,
3762
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
3763
                        email, course.course_language l,
3764
                        1 sort,
3765
                        category_code user_course_cat,
3766
                        access_start_date,
3767
                        access_end_date,
3768
                        session.id as session_id,
3769
                        session.name as session_name
3770
                    FROM $tbl_session_course_user as session_course_user
3771
                    INNER JOIN $tbl_course AS course
3772
                        ON course.id = session_course_user.c_id
3773
                    INNER JOIN $tbl_session as session
3774
                        ON session.id = session_course_user.session_id
3775
                    LEFT JOIN $tbl_user as user
3776
                        ON user.id = session_course_user.user_id OR session.id_coach = user.id
3777
                    WHERE
3778
                        session_course_user.session_id = $session_id AND (
3779
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
3780
                            OR session.id_coach = $user_id
3781
                        )
3782
                    ORDER BY i";
3783
                $course_list_sql_result = Database::query($sql);
3784
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3785
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
3786
                    $key = $result_row['session_id'].' - '.$result_row['code'];
3787
                    $personal_course_list[$key] = $result_row;
3788
                }
3789
            }
3790
        }
3791
3792
        foreach ($sessions as $enreg) {
3793
            $session_id = $enreg['id'];
3794
            $session_visibility = api_get_session_visibility($session_id);
3795
            if ($session_visibility == SESSION_INVISIBLE) {
3796
                continue;
3797
            }
3798
3799
            /* This query is very similar to the above query,
3800
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
3801
            $sql = "SELECT DISTINCT
3802
                course.code code,
3803
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
3804
                email,
3805
                course.course_language l,
3806
                1 sort,
3807
                category_code user_course_cat,
3808
                access_start_date,
3809
                access_end_date,
3810
                session.id as session_id,
3811
                session.name as session_name,
3812
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
3813
            FROM $tbl_session_course_user as session_course_user
3814
            INNER JOIN $tbl_course AS course
3815
            ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
3816
            INNER JOIN $tbl_session as session
3817
            ON session_course_user.session_id = session.id
3818
            LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
3819
            WHERE session_course_user.user_id = $user_id
3820
            ORDER BY i";
3821
3822
            $course_list_sql_result = Database::query($sql);
3823
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3824
                $result_row['course_info'] = api_get_course_info($result_row['code']);
3825
                $key = $result_row['session_id'].' - '.$result_row['code'];
3826
                if (!isset($personal_course_list[$key])) {
3827
                    $personal_course_list[$key] = $result_row;
3828
                }
3829
            }
3830
        }
3831
3832
        return $personal_course_list;
3833
    }
3834
3835
    /**
3836
     * Gives a list of courses for the given user in the given session.
3837
     *
3838
     * @param int $user_id
3839
     * @param int $session_id
3840
     *
3841
     * @return array list of statuses (session_id-course_code => status)
3842
     */
3843
    public static function get_courses_list_by_session($user_id, $session_id)
3844
    {
3845
        // Database Table Definitions
3846
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3847
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
3848
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3849
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3850
3851
        $user_id = (int) $user_id;
3852
        $session_id = (int) $session_id;
3853
        // We filter the courses from the URL
3854
        $join_access_url = $where_access_url = '';
3855
        if (api_get_multiple_access_url()) {
3856
            $urlId = api_get_current_access_url_id();
3857
            if ($urlId != -1) {
3858
                $tbl_url_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3859
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
3860
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
3861
            }
3862
        }
3863
3864
        /* This query is very similar to the query below, but it will check the
3865
        session_rel_course_user table if there are courses registered
3866
        to our user or not */
3867
        $sql = "SELECT DISTINCT
3868
                    c.title,
3869
                    c.visibility,
3870
                    c.id as real_id,
3871
                    c.code as course_code,
3872
                    sc.position,
3873
                    c.unsubscribe
3874
                FROM $tbl_session_course_user as scu
3875
                INNER JOIN $tbl_session_course sc
3876
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3877
                INNER JOIN $tableCourse as c
3878
                ON (scu.c_id = c.id)
3879
                $join_access_url
3880
                WHERE
3881
                    scu.user_id = $user_id AND
3882
                    scu.session_id = $session_id
3883
                    $where_access_url
3884
                ORDER BY sc.position ASC";
3885
3886
        $myCourseList = [];
3887
        $courses = [];
3888
        $result = Database::query($sql);
3889
        if (Database::num_rows($result) > 0) {
3890
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3891
                $result_row['status'] = 5;
3892
                if (!in_array($result_row['real_id'], $courses)) {
3893
                    $position = $result_row['position'];
3894
                    if (!isset($myCourseList[$position])) {
3895
                        $myCourseList[$position] = $result_row;
3896
                    } else {
3897
                        $myCourseList[] = $result_row;
3898
                    }
3899
                    $courses[] = $result_row['real_id'];
3900
                }
3901
            }
3902
        }
3903
3904
        if (api_is_allowed_to_create_course()) {
3905
            $sql = "SELECT DISTINCT
3906
                        c.title,
3907
                        c.visibility,
3908
                        c.id as real_id,
3909
                        c.code as course_code,
3910
                        sc.position,
3911
                        c.unsubscribe
3912
                    FROM $tbl_session_course_user as scu
3913
                    INNER JOIN $tbl_session as s
3914
                    ON (scu.session_id = s.id)
3915
                    INNER JOIN $tbl_session_course sc
3916
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3917
                    INNER JOIN $tableCourse as c
3918
                    ON (scu.c_id = c.id)
3919
                    $join_access_url
3920
                    WHERE
3921
                      s.id = $session_id AND
3922
                      (
3923
                        (scu.user_id = $user_id AND scu.status = 2) OR
3924
                        s.id_coach = $user_id
3925
                      )
3926
                    $where_access_url
3927
                    ORDER BY sc.position ASC";
3928
            $result = Database::query($sql);
3929
3930
            if (Database::num_rows($result) > 0) {
3931
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3932
                    $result_row['status'] = 2;
3933
                    if (!in_array($result_row['real_id'], $courses)) {
3934
                        $position = $result_row['position'];
3935
                        if (!isset($myCourseList[$position])) {
3936
                            $myCourseList[$position] = $result_row;
3937
                        } else {
3938
                            $myCourseList[] = $result_row;
3939
                        }
3940
                        $courses[] = $result_row['real_id'];
3941
                    }
3942
                }
3943
            }
3944
        }
3945
3946
        if (api_is_drh()) {
3947
            $sessionList = SessionManager::get_sessions_followed_by_drh($user_id);
3948
            $sessionList = array_keys($sessionList);
3949
            if (in_array($session_id, $sessionList)) {
3950
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3951
                if (!empty($courseList)) {
3952
                    foreach ($courseList as $course) {
3953
                        if (!in_array($course['id'], $courses)) {
3954
                            $position = $course['position'];
3955
                            if (!isset($myCourseList[$position])) {
3956
                                $myCourseList[$position] = $course;
3957
                            } else {
3958
                                $myCourseList[] = $course;
3959
                            }
3960
                        }
3961
                    }
3962
                }
3963
            }
3964
        } else {
3965
            //check if user is general coach for this session
3966
            $sessionInfo = api_get_session_info($session_id);
3967
            if ($sessionInfo['id_coach'] == $user_id) {
3968
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3969
                if (!empty($courseList)) {
3970
                    foreach ($courseList as $course) {
3971
                        if (!in_array($course['id'], $courses)) {
3972
                            $position = $course['position'];
3973
                            if (!isset($myCourseList[$position])) {
3974
                                $myCourseList[$position] = $course;
3975
                            } else {
3976
                                $myCourseList[] = $course;
3977
                            }
3978
                        }
3979
                    }
3980
                }
3981
            }
3982
        }
3983
3984
        if (!empty($myCourseList)) {
3985
            ksort($myCourseList);
3986
            $checkPosition = array_filter(array_column($myCourseList, 'position'));
3987
            if (empty($checkPosition)) {
3988
                // The session course list doesn't have any position,
3989
                // then order the course list by course code
3990
                $list = array_column($myCourseList, 'course_code');
3991
                array_multisort($myCourseList, SORT_ASC, $list);
3992
            }
3993
        }
3994
3995
        return $myCourseList;
3996
    }
3997
3998
    /**
3999
     * Get user id from a username.
4000
     *
4001
     * @param string $username
4002
     *
4003
     * @return int User ID (or false if not found)
4004
     */
4005
    public static function get_user_id_from_username($username)
4006
    {
4007
        if (empty($username)) {
4008
            return false;
4009
        }
4010
        $username = trim($username);
4011
        $username = Database::escape_string($username);
4012
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
4013
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
4014
        $res = Database::query($sql);
4015
4016
        if ($res === false) {
4017
            return false;
4018
        }
4019
        if (Database::num_rows($res) !== 1) {
4020
            return false;
4021
        }
4022
        $row = Database::fetch_array($res);
4023
4024
        return $row['id'];
4025
    }
4026
4027
    /**
4028
     * Get the users files upload from his share_folder.
4029
     *
4030
     * @param string $user_id      User ID
4031
     * @param string $course       course directory
4032
     * @param string $resourceType resource type: images, all
4033
     *
4034
     * @return string
4035
     */
4036
    public static function get_user_upload_files_by_course(
4037
        $user_id,
4038
        $course,
4039
        $resourceType = 'all'
4040
    ) {
4041
        $return = '';
4042
        $user_id = (int) $user_id;
4043
4044
        if (!empty($user_id) && !empty($course)) {
4045
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
4046
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
4047
            $file_list = [];
4048
4049
            if (is_dir($path)) {
4050
                $handle = opendir($path);
4051
                while ($file = readdir($handle)) {
4052
                    if ($file == '.' || $file == '..' || $file == '.htaccess' || is_dir($path.$file)) {
4053
                        continue; // skip current/parent directory and .htaccess
4054
                    }
4055
                    $file_list[] = $file;
4056
                }
4057
                if (count($file_list) > 0) {
4058
                    $return = "<h4>$course</h4>";
4059
                    $return .= '<ul class="thumbnails">';
4060
                }
4061
                $extensionList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif'];
4062
                foreach ($file_list as $file) {
4063
                    if ($resourceType == 'all') {
4064
                        $return .= '<li>
4065
                            <a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
4066
                    } elseif ($resourceType == 'images') {
4067
                        //get extension
4068
                        $ext = explode('.', $file);
4069
                        if (isset($ext[1]) && in_array($ext[1], $extensionList)) {
4070
                            $return .= '<li class="span2">
4071
                                            <a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
4072
                                                <img src="'.$web_path.urlencode($file).'" >
4073
                                            </a>
4074
                                        </li>';
4075
                        }
4076
                    }
4077
                }
4078
                if (count($file_list) > 0) {
4079
                    $return .= '</ul>';
4080
                }
4081
            }
4082
        }
4083
4084
        return $return;
4085
    }
4086
4087
    /**
4088
     * Gets the API key (or keys) and return them into an array.
4089
     *
4090
     * @param int     Optional user id (defaults to the result of api_get_user_id())
4091
     * @param string $api_service
4092
     *
4093
     * @return mixed Non-indexed array containing the list of API keys for this user, or FALSE on error
4094
     */
4095
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
4096
    {
4097
        if ($user_id != strval(intval($user_id))) {
4098
            return false;
4099
        }
4100
        if (empty($user_id)) {
4101
            $user_id = api_get_user_id();
4102
        }
4103
        if ($user_id === false) {
4104
            return false;
4105
        }
4106
        $service_name = Database::escape_string($api_service);
4107
        if (is_string($service_name) === false) {
4108
            return false;
4109
        }
4110
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
4111
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
4112
        $res = Database::query($sql);
4113
        if ($res === false) {
4114
            return false;
4115
        } //error during query
4116
        $num = Database::num_rows($res);
4117
        if ($num == 0) {
4118
            return false;
4119
        }
4120
        $list = [];
4121
        while ($row = Database::fetch_array($res)) {
4122
            $list[$row['id']] = $row['api_key'];
4123
        }
4124
4125
        return $list;
4126
    }
4127
4128
    /**
4129
     * Adds a new API key to the users' account.
4130
     *
4131
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
4132
     * @param string $api_service
4133
     *
4134
     * @return bool True on success, false on failure
4135
     */
4136
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
4137
    {
4138
        if ($user_id != strval(intval($user_id))) {
4139
            return false;
4140
        }
4141
        if (empty($user_id)) {
4142
            $user_id = api_get_user_id();
4143
        }
4144
        if ($user_id === false) {
4145
            return false;
4146
        }
4147
        $service_name = Database::escape_string($api_service);
4148
        if (is_string($service_name) === false) {
4149
            return false;
4150
        }
4151
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
4152
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
4153
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
4154
        $res = Database::query($sql);
4155
        if ($res === false) {
4156
            return false;
4157
        } //error during query
4158
        $num = Database::insert_id();
4159
4160
        return $num == 0 ? false : $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $num == 0 ? false : $num also could return the type string which is incompatible with the documented return type boolean.
Loading history...
4161
    }
4162
4163
    /**
4164
     * Deletes an API key from the user's account.
4165
     *
4166
     * @param   int     API key's internal ID
4167
     *
4168
     * @return bool True on success, false on failure
4169
     */
4170
    public static function delete_api_key($key_id)
4171
    {
4172
        if ($key_id != strval(intval($key_id))) {
4173
            return false;
4174
        }
4175
        if ($key_id === false) {
4176
            return false;
4177
        }
4178
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
4179
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
4180
        $res = Database::query($sql);
4181
        if ($res === false) {
4182
            return false;
4183
        } //error during query
4184
        $num = Database::num_rows($res);
4185
        if ($num !== 1) {
4186
            return false;
4187
        }
4188
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
4189
        $res = Database::query($sql);
4190
        if ($res === false) {
4191
            return false;
4192
        } //error during query
4193
4194
        return true;
4195
    }
4196
4197
    /**
4198
     * Regenerate an API key from the user's account.
4199
     *
4200
     * @param   int     user ID (defaults to the results of api_get_user_id())
4201
     * @param   string  API key's internal ID
4202
     *
4203
     * @return int num
4204
     */
4205
    public static function update_api_key($user_id, $api_service)
4206
    {
4207
        if ($user_id != strval(intval($user_id))) {
4208
            return false;
4209
        }
4210
        if ($user_id === false) {
4211
            return false;
4212
        }
4213
        $service_name = Database::escape_string($api_service);
4214
        if (is_string($service_name) === false) {
4215
            return false;
4216
        }
4217
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
4218
        $sql = "SELECT id FROM $t_api
4219
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
4220
        $res = Database::query($sql);
4221
        $num = Database::num_rows($res);
4222
        if ($num == 1) {
4223
            $id_key = Database::fetch_array($res, 'ASSOC');
4224
            self::delete_api_key($id_key['id']);
4225
            $num = self::add_api_key($user_id, $api_service);
4226
        } elseif ($num == 0) {
4227
            $num = self::add_api_key($user_id, $api_service);
4228
        }
4229
4230
        return $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $num also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
4231
    }
4232
4233
    /**
4234
     * @param   int     user ID (defaults to the results of api_get_user_id())
4235
     * @param   string    API key's internal ID
4236
     *
4237
     * @return int row ID, or return false if not found
4238
     */
4239
    public static function get_api_key_id($user_id, $api_service)
4240
    {
4241
        if ($user_id != strval(intval($user_id))) {
4242
            return false;
4243
        }
4244
        if ($user_id === false) {
4245
            return false;
4246
        }
4247
        if (empty($api_service)) {
4248
            return false;
4249
        }
4250
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
4251
        $api_service = Database::escape_string($api_service);
4252
        $sql = "SELECT id FROM $t_api
4253
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
4254
        $res = Database::query($sql);
4255
        if (Database::num_rows($res) < 1) {
4256
            return false;
4257
        }
4258
        $row = Database::fetch_array($res, 'ASSOC');
4259
4260
        return $row['id'];
4261
    }
4262
4263
    /**
4264
     * Checks if a user_id is platform admin.
4265
     *
4266
     * @param   int user ID
4267
     *
4268
     * @return bool True if is admin, false otherwise
4269
     *
4270
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
4271
     */
4272
    public static function is_admin($user_id)
4273
    {
4274
        $user_id = (int) $user_id;
4275
        if (empty($user_id)) {
4276
            return false;
4277
        }
4278
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
4279
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
4280
        $res = Database::query($sql);
4281
4282
        return Database::num_rows($res) === 1;
4283
    }
4284
4285
    /**
4286
     * Get the total count of users.
4287
     *
4288
     * @param int $status        Status of users to be counted
4289
     * @param int $access_url_id Access URL ID (optional)
4290
     * @param int $active
4291
     *
4292
     * @return mixed Number of users or false on error
4293
     */
4294
    public static function get_number_of_users($status = 0, $access_url_id = 1, $active = null)
4295
    {
4296
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
4297
        $t_a = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4298
4299
        if (api_is_multiple_url_enabled()) {
4300
            $sql = "SELECT count(u.id)
4301
                    FROM $t_u u
4302
                    INNER JOIN $t_a url_user
4303
                    ON (u.id = url_user.user_id)
4304
                    WHERE url_user.access_url_id = $access_url_id
4305
            ";
4306
        } else {
4307
            $sql = "SELECT count(u.id)
4308
                    FROM $t_u u
4309
                    WHERE 1 = 1 ";
4310
        }
4311
4312
        if (is_int($status) && $status > 0) {
4313
            $status = (int) $status;
4314
            $sql .= " AND u.status = $status ";
4315
        }
4316
4317
        if ($active !== null) {
4318
            $active = (int) $active;
4319
            $sql .= " AND u.active = $active ";
4320
        }
4321
4322
        $res = Database::query($sql);
4323
        if (Database::num_rows($res) === 1) {
4324
            return (int) Database::result($res, 0, 0);
4325
        }
4326
4327
        return false;
4328
    }
4329
4330
    /**
4331
     * Gets the tags of a specific field_id
4332
     * USER TAGS.
4333
     *
4334
     * Instructions to create a new user tag by Julio Montoya <[email protected]>
4335
     *
4336
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible.
4337
     *    Called it "books" for example.
4338
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
4339
     * 3. All the tags are registered in the user_tag table and the relationship between user and tags is in the user_rel_tag table
4340
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
4341
     * 5. Test and enjoy.
4342
     *
4343
     * @param string $tag
4344
     * @param int    $field_id      field_id
4345
     * @param string $return_format how we are going to result value in array or in a string (json)
4346
     * @param $limit
4347
     *
4348
     * @return mixed
4349
     */
4350
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
4351
    {
4352
        // database table definition
4353
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4354
        $field_id = (int) $field_id;
4355
        $limit = (int) $limit;
4356
        $tag = trim(Database::escape_string($tag));
4357
4358
        // all the information of the field
4359
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
4360
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
4361
        $result = Database::query($sql);
4362
        $return = [];
4363
        if (Database::num_rows($result) > 0) {
4364
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4365
                $return[] = ['id' => $row['tag'], 'text' => $row['tag']];
4366
            }
4367
        }
4368
        if ($return_format === 'json') {
4369
            $return = json_encode($return);
4370
        }
4371
4372
        return $return;
4373
    }
4374
4375
    /**
4376
     * @param int $field_id
4377
     * @param int $limit
4378
     *
4379
     * @return array
4380
     */
4381
    public static function get_top_tags($field_id, $limit = 100)
4382
    {
4383
        // database table definition
4384
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4385
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
4386
        $field_id = (int) $field_id;
4387
        $limit = (int) $limit;
4388
        // all the information of the field
4389
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
4390
                INNER JOIN $table_user_tag ut
4391
                ON (ut.id = uv.tag_id)
4392
                WHERE field_id = $field_id
4393
                GROUP BY tag_id
4394
                ORDER BY count DESC
4395
                LIMIT $limit";
4396
        $result = Database::query($sql);
4397
        $return = [];
4398
        if (Database::num_rows($result) > 0) {
4399
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4400
                $return[] = $row;
4401
            }
4402
        }
4403
4404
        return $return;
4405
    }
4406
4407
    /**
4408
     * Get user's tags.
4409
     *
4410
     * @param int $user_id
4411
     * @param int $field_id
4412
     *
4413
     * @return array
4414
     */
4415
    public static function get_user_tags($user_id, $field_id)
4416
    {
4417
        // database table definition
4418
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4419
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
4420
        $field_id = (int) $field_id;
4421
        $user_id = (int) $user_id;
4422
4423
        // all the information of the field
4424
        $sql = "SELECT ut.id, tag, count
4425
                FROM $table_user_tag ut
4426
                INNER JOIN $table_user_tag_values uv
4427
                ON (uv.tag_id=ut.ID)
4428
                WHERE field_id = $field_id AND user_id = $user_id
4429
                ORDER BY tag";
4430
        $result = Database::query($sql);
4431
        $return = [];
4432
        if (Database::num_rows($result) > 0) {
4433
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4434
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
4435
            }
4436
        }
4437
4438
        return $return;
4439
    }
4440
4441
    /**
4442
     * Get user's tags.
4443
     *
4444
     * @param int  $user_id
4445
     * @param int  $field_id
4446
     * @param bool $show_links show links or not
4447
     *
4448
     * @return string
4449
     */
4450
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
4451
    {
4452
        // database table definition
4453
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4454
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
4455
        $field_id = (int) $field_id;
4456
        $user_id = (int) $user_id;
4457
4458
        // all the information of the field
4459
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
4460
                INNER JOIN $table_user_tag_values uv
4461
                ON (uv.tag_id = ut.id)
4462
                WHERE field_id = $field_id AND user_id = $user_id
4463
                ORDER BY tag";
4464
4465
        $result = Database::query($sql);
4466
        $return = [];
4467
        if (Database::num_rows($result) > 0) {
4468
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4469
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
4470
            }
4471
        }
4472
        $user_tags = $return;
4473
        $tag_tmp = [];
4474
        foreach ($user_tags as $tag) {
4475
            if ($show_links) {
4476
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.
4477
                    $tag['tag'].
4478
                '</a>';
4479
            } else {
4480
                $tag_tmp[] = $tag['tag'];
4481
            }
4482
        }
4483
4484
        if (is_array($user_tags) && count($user_tags) > 0) {
4485
            return implode(', ', $tag_tmp);
4486
        } else {
4487
            return '';
4488
        }
4489
    }
4490
4491
    /**
4492
     * Get the tag id.
4493
     *
4494
     * @param int $tag
4495
     * @param int $field_id
4496
     *
4497
     * @return int returns 0 if fails otherwise the tag id
4498
     */
4499
    public static function get_tag_id($tag, $field_id)
4500
    {
4501
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4502
        $tag = Database::escape_string($tag);
4503
        $field_id = (int) $field_id;
4504
        //with COLLATE latin1_bin to select query in a case sensitive mode
4505
        $sql = "SELECT id FROM $table_user_tag
4506
                WHERE tag LIKE '$tag' AND field_id = $field_id";
4507
        $result = Database::query($sql);
4508
        if (Database::num_rows($result) > 0) {
4509
            $row = Database::fetch_array($result, 'ASSOC');
4510
4511
            return $row['id'];
4512
        } else {
4513
            return 0;
4514
        }
4515
    }
4516
4517
    /**
4518
     * Get the tag id.
4519
     *
4520
     * @param int $tag_id
4521
     * @param int $field_id
4522
     *
4523
     * @return int 0 if fails otherwise the tag id
4524
     */
4525
    public static function get_tag_id_from_id($tag_id, $field_id)
4526
    {
4527
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4528
        $tag_id = (int) $tag_id;
4529
        $field_id = (int) $field_id;
4530
        $sql = "SELECT id FROM $table_user_tag
4531
                WHERE id = '$tag_id' AND field_id = $field_id";
4532
        $result = Database::query($sql);
4533
        if (Database::num_rows($result) > 0) {
4534
            $row = Database::fetch_array($result, 'ASSOC');
4535
4536
            return $row['id'];
4537
        } else {
4538
            return false;
4539
        }
4540
    }
4541
4542
    /**
4543
     * Adds a user-tag value.
4544
     *
4545
     * @param mixed $tag
4546
     * @param int   $user_id
4547
     * @param int   $field_id field id of the tag
4548
     *
4549
     * @return bool True if the tag was inserted or updated. False otherwise.
4550
     *              The return value doesn't take into account *values* added to the tag.
4551
     *              Only the creation/update of the tag field itself.
4552
     */
4553
    public static function add_tag($tag, $user_id, $field_id)
4554
    {
4555
        // database table definition
4556
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4557
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
4558
        $tag = trim(Database::escape_string($tag));
4559
        $user_id = (int) $user_id;
4560
        $field_id = (int) $field_id;
4561
4562
        $tag_id = self::get_tag_id($tag, $field_id);
4563
4564
        /* IMPORTANT
4565
         *  @todo we don't create tags with numbers
4566
         *
4567
         */
4568
        if (is_numeric($tag)) {
4569
            //the form is sending an id this means that the user select it from the list so it MUST exists
4570
            /* $new_tag_id = self::get_tag_id_from_id($tag,$field_id);
4571
              if ($new_tag_id !== false) {
4572
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
4573
              $result = Database::query($sql);
4574
              $last_insert_id = $new_tag_id;
4575
              } else {
4576
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
4577
              $result = Database::query($sql);
4578
              $last_insert_id = Database::insert_id();
4579
              } */
4580
        }
4581
4582
        //this is a new tag
4583
        if ($tag_id == 0) {
4584
            //the tag doesn't exist
4585
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
4586
            Database::query($sql);
4587
            $last_insert_id = Database::insert_id();
4588
        } else {
4589
            //the tag exists we update it
4590
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
4591
            Database::query($sql);
4592
            $last_insert_id = $tag_id;
4593
        }
4594
4595
        if (!empty($last_insert_id) && ($last_insert_id != 0)) {
4596
            //we insert the relationship user-tag
4597
            $sql = "SELECT tag_id FROM $table_user_tag_values
4598
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
4599
            $result = Database::query($sql);
4600
            //if the relationship does not exist we create it
4601
            if (Database::num_rows($result) == 0) {
4602
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
4603
                Database::query($sql);
4604
            }
4605
4606
            return true;
4607
        }
4608
4609
        return false;
4610
    }
4611
4612
    /**
4613
     * Deletes an user tag.
4614
     *
4615
     * @param int $user_id
4616
     * @param int $field_id
4617
     */
4618
    public static function delete_user_tags($user_id, $field_id)
4619
    {
4620
        // database table definition
4621
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4622
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
4623
        $user_id = (int) $user_id;
4624
4625
        $tags = self::get_user_tags($user_id, $field_id);
4626
        if (is_array($tags) && count($tags) > 0) {
4627
            foreach ($tags as $key => $tag) {
4628
                if ($tag['count'] > '0') {
4629
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
4630
                    Database::query($sql);
4631
                }
4632
                $sql = "DELETE FROM $table_user_tag_values
4633
                        WHERE user_id = $user_id AND tag_id = $key";
4634
                Database::query($sql);
4635
            }
4636
        }
4637
    }
4638
4639
    /**
4640
     * Process the tag list comes from the UserManager::update_extra_field_value() function.
4641
     *
4642
     * @param array $tags     the tag list that will be added
4643
     * @param int   $user_id
4644
     * @param int   $field_id
4645
     *
4646
     * @return bool
4647
     */
4648
    public static function process_tags($tags, $user_id, $field_id)
4649
    {
4650
        // We loop the tags and add it to the DB
4651
        if (is_array($tags)) {
4652
            foreach ($tags as $tag) {
4653
                self::add_tag($tag, $user_id, $field_id);
4654
            }
4655
        } else {
4656
            self::add_tag($tags, $user_id, $field_id);
4657
        }
4658
4659
        return true;
4660
    }
4661
4662
    /**
4663
     * Returns a list of all administrators.
4664
     *
4665
     * @return array
4666
     */
4667
    public static function get_all_administrators()
4668
    {
4669
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4670
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
4671
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4672
        $access_url_id = api_get_current_access_url_id();
4673
        if (api_get_multiple_access_url()) {
4674
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
4675
                    FROM $tbl_url_rel_user as url
4676
                    INNER JOIN $table_admin as admin
4677
                    ON (admin.user_id=url.user_id)
4678
                    INNER JOIN $table_user u
4679
                    ON (u.id=admin.user_id)
4680
                    WHERE access_url_id ='".$access_url_id."'";
4681
        } else {
4682
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
4683
                    FROM $table_admin as admin
4684
                    INNER JOIN $table_user u
4685
                    ON (u.id=admin.user_id)";
4686
        }
4687
        $result = Database::query($sql);
4688
        $return = [];
4689
        if (Database::num_rows($result) > 0) {
4690
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4691
                $return[$row['user_id']] = $row;
4692
            }
4693
        }
4694
4695
        return $return;
4696
    }
4697
4698
    /**
4699
     * Search an user (tags, first name, last name and email ).
4700
     *
4701
     * @param string $tag
4702
     * @param int    $field_id        field id of the tag
4703
     * @param int    $from            where to start in the query
4704
     * @param int    $number_of_items
4705
     * @param bool   $getCount        get count or not
4706
     *
4707
     * @return array
4708
     */
4709
    public static function get_all_user_tags(
4710
        $tag,
4711
        $field_id = 0,
4712
        $from = 0,
4713
        $number_of_items = 10,
4714
        $getCount = false
4715
    ) {
4716
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
4717
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
4718
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
4719
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4720
4721
        $field_id = intval($field_id);
4722
        $from = intval($from);
4723
        $number_of_items = intval($number_of_items);
4724
4725
        $where_field = "";
4726
        $where_extra_fields = self::get_search_form_where_extra_fields();
4727
        if ($field_id != 0) {
4728
            $where_field = " field_id = $field_id AND ";
4729
        }
4730
4731
        // all the information of the field
4732
        if ($getCount) {
4733
            $select = "SELECT count(DISTINCT u.id) count";
4734
        } else {
4735
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, picture_uri";
4736
        }
4737
4738
        $sql = " $select
4739
                FROM $user_table u
4740
                INNER JOIN $access_url_rel_user_table url_rel_user
4741
                ON (u.id = url_rel_user.user_id)
4742
                LEFT JOIN $table_user_tag_values uv
4743
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
4744
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
4745
                WHERE
4746
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
4747
                    (
4748
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
4749
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
4750
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
4751
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
4752
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
4753
                     )
4754
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
4755
                     AND url_rel_user.access_url_id=".api_get_current_access_url_id();
4756
4757
        $keyword_active = true;
4758
        // only active users
4759
        if ($keyword_active) {
4760
            $sql .= " AND u.active='1'";
4761
        }
4762
        // avoid anonymous
4763
        $sql .= " AND u.status <> 6 ";
4764
        $sql .= " ORDER BY username";
4765
        $sql .= " LIMIT $from , $number_of_items";
4766
4767
        $result = Database::query($sql);
4768
        $return = [];
4769
4770
        if (Database::num_rows($result) > 0) {
4771
            if ($getCount) {
4772
                $row = Database::fetch_array($result, 'ASSOC');
4773
4774
                return $row['count'];
4775
            }
4776
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4777
                $return[$row['id']] = $row;
4778
            }
4779
        }
4780
4781
        return $return;
4782
    }
4783
4784
    /**
4785
     * Get extra filterable user fields (only type select).
4786
     *
4787
     * @return array Array of extra fields as [int => ['name' => ..., 'variable' => ..., 'data' => ...]] (
4788
     *               or empty array if no extra field)
4789
     */
4790
    public static function getExtraFilterableFields()
4791
    {
4792
        $extraFieldList = self::get_extra_fields();
4793
        $fields = [];
4794
        if (is_array($extraFieldList)) {
4795
            foreach ($extraFieldList as $extraField) {
4796
                // If is enabled to filter and is a "<select>" field type
4797
                if ($extraField[8] == 1 && $extraField[2] == 4) {
4798
                    $fields[] = [
4799
                        'name' => $extraField[3],
4800
                        'variable' => $extraField[1],
4801
                        'data' => $extraField[9],
4802
                    ];
4803
                }
4804
            }
4805
        }
4806
4807
        return $fields;
4808
    }
4809
4810
    /**
4811
     * Get extra where clauses for finding users based on extra filterable user fields (type select).
4812
     *
4813
     * @return string With AND clauses based on user's ID which have the values to search in extra user fields
4814
     *                (or empty if no extra field exists)
4815
     */
4816
    public static function get_search_form_where_extra_fields()
4817
    {
4818
        $useExtraFields = false;
4819
        $extraFields = self::getExtraFilterableFields();
4820
        $extraFieldResult = [];
4821
        if (is_array($extraFields) && count($extraFields) > 0) {
4822
            foreach ($extraFields as $extraField) {
4823
                $varName = 'field_'.$extraField['variable'];
4824
                if (self::is_extra_field_available($extraField['variable'])) {
4825
                    if (isset($_GET[$varName]) && $_GET[$varName] != '0') {
4826
                        $useExtraFields = true;
4827
                        $extraFieldResult[] = self::get_extra_user_data_by_value(
4828
                            $extraField['variable'],
4829
                            $_GET[$varName]
4830
                        );
4831
                    }
4832
                }
4833
            }
4834
        }
4835
4836
        if ($useExtraFields) {
4837
            $finalResult = [];
4838
            if (count($extraFieldResult) > 1) {
4839
                for ($i = 0; $i < count($extraFieldResult) - 1; $i++) {
4840
                    if (is_array($extraFieldResult[$i]) && is_array($extraFieldResult[$i + 1])) {
4841
                        $finalResult = array_intersect($extraFieldResult[$i], $extraFieldResult[$i + 1]);
4842
                    }
4843
                }
4844
            } else {
4845
                $finalResult = $extraFieldResult[0];
4846
            }
4847
4848
            if (is_array($finalResult) && count($finalResult) > 0) {
4849
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
4850
            } else {
4851
                //no results
4852
                $whereFilter = " AND u.id  = -1 ";
4853
            }
4854
4855
            return $whereFilter;
4856
        }
4857
4858
        return '';
4859
    }
4860
4861
    /**
4862
     * Show the search form.
4863
     *
4864
     * @param string $query the value of the search box
4865
     *
4866
     * @throws Exception
4867
     *
4868
     * @return string HTML form
4869
     */
4870
    public static function get_search_form($query, $defaultParams = [])
4871
    {
4872
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
4873
        $form = new FormValidator(
4874
            'search_user',
4875
            'get',
4876
            api_get_path(WEB_PATH).'main/social/search.php',
4877
            '',
4878
            [],
4879
            FormValidator::LAYOUT_HORIZONTAL
4880
        );
4881
4882
        $query = Security::remove_XSS($query);
4883
4884
        if (!empty($query)) {
4885
            $form->addHeader(get_lang('Results').' "'.$query.'"');
4886
        }
4887
4888
        $form->addText(
4889
            'q',
4890
            get_lang('UsersGroups'),
4891
            false,
4892
            [
4893
                'id' => 'q',
4894
            ]
4895
        );
4896
        $options = [
4897
            0 => get_lang('Select'),
4898
            1 => get_lang('User'),
4899
            2 => get_lang('Group'),
4900
        ];
4901
        $form->addSelect(
4902
            'search_type',
4903
            get_lang('Type'),
4904
            $options,
4905
            ['onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type']
4906
        );
4907
4908
        // Extra fields
4909
        $extraFields = self::getExtraFilterableFields();
4910
        $defaults = [];
4911
        if (is_array($extraFields) && count($extraFields) > 0) {
4912
            foreach ($extraFields as $extraField) {
4913
                $varName = 'field_'.$extraField['variable'];
4914
                $options = [
4915
                    0 => get_lang('Select'),
4916
                ];
4917
                foreach ($extraField['data'] as $option) {
4918
                    if (isset($_GET[$varName])) {
4919
                        if ($_GET[$varName] == $option[1]) {
4920
                            $defaults[$option[1]] = true;
4921
                        }
4922
                    }
4923
4924
                    $options[$option[1]] = $option[1];
4925
                }
4926
                $form->addSelect($varName, $extraField['name'], $options);
4927
            }
4928
        }
4929
4930
        $defaults['search_type'] = (int) $searchType;
4931
        $defaults['q'] = $query;
4932
4933
        if (!empty($defaultParams)) {
4934
            $defaults = array_merge($defaults, $defaultParams);
4935
        }
4936
        $form->setDefaults($defaults);
4937
        $form->addButtonSearch(get_lang('Search'));
4938
4939
        $js = '<script>
4940
        extra_field_toogle();
4941
        function extra_field_toogle() {
4942
            if (jQuery("select[name=search_type]").val() != "1") {
4943
                jQuery(".extra_field").hide();
4944
            } else {
4945
                jQuery(".extra_field").show();
4946
            }
4947
        }
4948
        </script>';
4949
4950
        return $js.$form->returnForm();
4951
    }
4952
4953
    /**
4954
     * Shows the user menu.
4955
     */
4956
    public static function show_menu()
4957
    {
4958
        echo '<div class="actions">';
4959
        echo '<a href="/main/auth/profile.php">'.
4960
            Display::return_icon('profile.png').' '.get_lang('PersonalData').'</a>';
4961
        echo '<a href="/main/messages/inbox.php">'.
4962
            Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
4963
        echo '<a href="/main/messages/outbox.php">'.
4964
            Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
4965
        echo '<span style="float:right; padding-top:7px;">'.
4966
        '<a href="/main/auth/profile.php?show=1">'.
4967
            Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
4968
        echo '</span>';
4969
        echo '</div>';
4970
    }
4971
4972
    /**
4973
     * Allow to register contact to social network.
4974
     *
4975
     * @param int $friend_id     user friend id
4976
     * @param int $my_user_id    user id
4977
     * @param int $relation_type relation between users see constants definition
4978
     *
4979
     * @return bool
4980
     */
4981
    public static function relate_users($friend_id, $my_user_id, $relation_type)
4982
    {
4983
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4984
4985
        $friend_id = (int) $friend_id;
4986
        $my_user_id = (int) $my_user_id;
4987
        $relation_type = (int) $relation_type;
4988
4989
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4990
                WHERE
4991
                    friend_user_id='.$friend_id.' AND
4992
                    user_id='.$my_user_id.' AND
4993
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4994
        $result = Database::query($sql);
4995
        $row = Database::fetch_array($result, 'ASSOC');
4996
        $current_date = api_get_utc_datetime();
4997
4998
        if ($row['count'] == 0) {
4999
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
5000
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
5001
            Database::query($sql);
5002
5003
            return true;
5004
        }
5005
5006
        $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
5007
                WHERE
5008
                    friend_user_id='.$friend_id.' AND
5009
                    user_id='.$my_user_id.' AND
5010
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
5011
        $result = Database::query($sql);
5012
        $row = Database::fetch_array($result, 'ASSOC');
5013
5014
        if ($row['count'] == 1) {
5015
            //only for the case of a RRHH or a Student BOSS
5016
            if ($row['relation_type'] != $relation_type &&
5017
                ($relation_type == USER_RELATION_TYPE_RRHH || $relation_type == USER_RELATION_TYPE_BOSS)
5018
            ) {
5019
                $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
5020
                        VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
5021
            } else {
5022
                $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
5023
                        WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
5024
            }
5025
            Database::query($sql);
5026
5027
            return true;
5028
        }
5029
5030
        return false;
5031
    }
5032
5033
    /**
5034
     * Deletes a contact.
5035
     *
5036
     * @param bool   $friend_id
5037
     * @param bool   $real_removed          true will delete ALL friends relationship
5038
     * @param string $with_status_condition
5039
     *
5040
     * @author isaac flores paz <[email protected]>
5041
     * @author Julio Montoya <[email protected]> Cleaning code
5042
     */
5043
    public static function remove_user_rel_user(
5044
        $friend_id,
5045
        $real_removed = false,
5046
        $with_status_condition = ''
5047
    ) {
5048
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5049
        $tbl_my_message = Database::get_main_table(TABLE_MESSAGE);
5050
        $friend_id = (int) $friend_id;
5051
        $user_id = api_get_user_id();
5052
5053
        if ($real_removed) {
5054
            $extra_condition = '';
5055
            if ($with_status_condition != '') {
5056
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
5057
            }
5058
            $sql = 'DELETE FROM '.$tbl_my_friend.'
5059
                    WHERE
5060
                        relation_type <> '.USER_RELATION_TYPE_RRHH.' AND
5061
                        friend_user_id='.$friend_id.' '.$extra_condition;
5062
            Database::query($sql);
5063
            $sql = 'DELETE FROM '.$tbl_my_friend.'
5064
                   WHERE
5065
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' AND
5066
                    user_id='.$friend_id.' '.$extra_condition;
5067
            Database::query($sql);
5068
        } else {
5069
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
5070
                    WHERE
5071
                        user_id='.$user_id.' AND
5072
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
5073
                        friend_user_id='.$friend_id;
5074
            $result = Database::query($sql);
5075
            $row = Database::fetch_array($result, 'ASSOC');
5076
            if ($row['count'] == 1) {
5077
                //Delete user rel user
5078
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
5079
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
5080
5081
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
5082
                          WHERE
5083
                                user_receiver_id='.$user_id.' AND
5084
                                user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
5085
                // Delete user
5086
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
5087
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
5088
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
5089
                           WHERE
5090
                                user_receiver_id='.$friend_id.' AND
5091
                                user_sender_id='.$user_id.' AND
5092
                                update_date="0000-00-00 00:00:00" ';
5093
                Database::query($sql_i);
5094
                Database::query($sql_j);
5095
                Database::query($sql_ij);
5096
                Database::query($sql_ji);
5097
            }
5098
        }
5099
5100
        // Delete accepted invitations
5101
        $sql = "DELETE FROM $tbl_my_message
5102
                WHERE
5103
                    msg_status = ".MESSAGE_STATUS_INVITATION_ACCEPTED." AND
5104
                    (
5105
                        user_receiver_id = $user_id AND
5106
                        user_sender_id = $friend_id
5107
                    ) OR
5108
                    (
5109
                        user_sender_id = $user_id AND
5110
                        user_receiver_id = $friend_id
5111
                    )
5112
        ";
5113
        Database::query($sql);
5114
    }
5115
5116
    /**
5117
     * @param int $userId
5118
     *
5119
     * @return array
5120
     */
5121
    public static function getDrhListFromUser($userId)
5122
    {
5123
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
5124
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5125
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5126
        $userId = (int) $userId;
5127
5128
        $orderBy = null;
5129
        if (api_is_western_name_order()) {
5130
            $orderBy .= ' ORDER BY firstname, lastname ';
5131
        } else {
5132
            $orderBy .= ' ORDER BY lastname, firstname ';
5133
        }
5134
5135
        $sql = "SELECT u.id, username, u.firstname, u.lastname
5136
                FROM $tblUser u
5137
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
5138
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
5139
                WHERE
5140
                    access_url_id = ".api_get_current_access_url_id()." AND
5141
                    uru.user_id = '$userId' AND
5142
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
5143
                $orderBy
5144
                ";
5145
        $result = Database::query($sql);
5146
5147
        return Database::store_result($result);
5148
    }
5149
5150
    /**
5151
     * get users followed by human resource manager.
5152
     *
5153
     * @param int    $userId
5154
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
5155
     * @param bool   $getOnlyUserId
5156
     * @param bool   $getSql
5157
     * @param bool   $getCount
5158
     * @param int    $from
5159
     * @param int    $numberItems
5160
     * @param int    $column
5161
     * @param string $direction
5162
     * @param int    $active
5163
     * @param string $lastConnectionDate
5164
     *
5165
     * @return array users
5166
     */
5167
    public static function get_users_followed_by_drh(
5168
        $userId,
5169
        $userStatus = 0,
5170
        $getOnlyUserId = false,
5171
        $getSql = false,
5172
        $getCount = false,
5173
        $from = null,
5174
        $numberItems = null,
5175
        $column = null,
5176
        $direction = null,
5177
        $active = null,
5178
        $lastConnectionDate = null
5179
    ) {
5180
        return self::getUsersFollowedByUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::getUsersFol...astConnectionDate, DRH) also could return the type string which is incompatible with the documented return type array.
Loading history...
5181
            $userId,
5182
            $userStatus,
5183
            $getOnlyUserId,
5184
            $getSql,
5185
            $getCount,
5186
            $from,
5187
            $numberItems,
5188
            $column,
5189
            $direction,
5190
            $active,
5191
            $lastConnectionDate,
5192
            DRH
5193
        );
5194
    }
5195
5196
    /**
5197
     * Get users followed by human resource manager.
5198
     *
5199
     * @param int    $userId
5200
     * @param int    $userStatus         Filter users by status (STUDENT, COURSEMANAGER, etc)
5201
     * @param bool   $getOnlyUserId
5202
     * @param bool   $getSql
5203
     * @param bool   $getCount
5204
     * @param int    $from
5205
     * @param int    $numberItems
5206
     * @param int    $column
5207
     * @param string $direction
5208
     * @param int    $active
5209
     * @param string $lastConnectionDate
5210
     * @param int    $status             the function is called by who? COURSEMANAGER, DRH?
5211
     * @param string $keyword
5212
     *
5213
     * @return mixed Users list (array) or the SQL query if $getSQL was set to true
5214
     */
5215
    public static function getUsersFollowedByUser(
5216
        $userId,
5217
        $userStatus = null,
5218
        $getOnlyUserId = false,
5219
        $getSql = false,
5220
        $getCount = false,
5221
        $from = null,
5222
        $numberItems = null,
5223
        $column = null,
5224
        $direction = null,
5225
        $active = null,
5226
        $lastConnectionDate = null,
5227
        $status = null,
5228
        $keyword = null
5229
    ) {
5230
        // Database Table Definitions
5231
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5232
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5233
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5234
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5235
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5236
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5237
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
5238
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
5239
5240
        $userId = (int) $userId;
5241
        $limitCondition = '';
5242
5243
        if (isset($from) && isset($numberItems)) {
5244
            $from = (int) $from;
5245
            $numberItems = (int) $numberItems;
5246
            $limitCondition = "LIMIT $from, $numberItems";
5247
        }
5248
5249
        $column = Database::escape_string($column);
5250
        $direction = in_array(strtolower($direction), ['asc', 'desc']) ? $direction : null;
5251
5252
        $userConditions = '';
5253
        if (!empty($userStatus)) {
5254
            $userConditions .= ' AND u.status = '.intval($userStatus);
5255
        }
5256
5257
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
5258
        if ($getOnlyUserId) {
5259
            $select = " SELECT DISTINCT u.id user_id";
5260
        }
5261
5262
        $masterSelect = "SELECT DISTINCT * FROM ";
5263
5264
        if ($getCount) {
5265
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
5266
            $select = " SELECT DISTINCT(u.id) user_id";
5267
        }
5268
5269
        if (!is_null($active)) {
5270
            $active = intval($active);
5271
            $userConditions .= " AND u.active = $active ";
5272
        }
5273
5274
        if (!empty($keyword)) {
5275
            $keyword = Database::escape_string($keyword);
5276
            $userConditions .= " AND (
5277
                u.username LIKE '%$keyword%' OR
5278
                u.firstname LIKE '%$keyword%' OR
5279
                u.lastname LIKE '%$keyword%' OR
5280
                u.official_code LIKE '%$keyword%' OR
5281
                u.email LIKE '%$keyword%'
5282
            )";
5283
        }
5284
5285
        if (!empty($lastConnectionDate)) {
5286
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
5287
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
5288
        }
5289
5290
        $sessionConditionsCoach = null;
5291
        $sessionConditionsTeacher = null;
5292
        $drhConditions = null;
5293
        $teacherSelect = null;
5294
5295
        switch ($status) {
5296
            case DRH:
5297
                $drhConditions .= " AND
5298
                    friend_user_id = '$userId' AND
5299
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
5300
                ";
5301
                break;
5302
            case COURSEMANAGER:
5303
                $drhConditions .= " AND
5304
                    friend_user_id = '$userId' AND
5305
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
5306
                ";
5307
5308
                $sessionConditionsCoach .= " AND
5309
                    (s.id_coach = '$userId')
5310
                ";
5311
5312
                $sessionConditionsTeacher .= " AND
5313
                    (scu.status = 2 AND scu.user_id = '$userId')
5314
                ";
5315
5316
                $teacherSelect =
5317
                "UNION ALL (
5318
                        $select
5319
                        FROM $tbl_user u
5320
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
5321
                        WHERE
5322
                            (
5323
                                sru.session_id IN (
5324
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
5325
                                    $tbl_session_rel_access_url session_rel_access_rel_user
5326
                                    ON session_rel_access_rel_user.session_id = s.id
5327
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
5328
                                    $sessionConditionsCoach
5329
                                ) OR sru.session_id IN (
5330
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
5331
                                    INNER JOIN $tbl_session_rel_access_url url
5332
                                    ON (url.session_id = s.id)
5333
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
5334
                                    ON (scu.session_id = s.id)
5335
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
5336
                                    $sessionConditionsTeacher
5337
                                )
5338
                            )
5339
                            $userConditions
5340
                    )
5341
                    UNION ALL(
5342
                        $select
5343
                        FROM $tbl_user u
5344
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
5345
                        WHERE cu.c_id IN (
5346
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
5347
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
5348
                        )
5349
                        $userConditions
5350
                    )"
5351
                ;
5352
                break;
5353
            case STUDENT_BOSS:
5354
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
5355
                break;
5356
            case HRM_REQUEST:
5357
                $drhConditions .= " AND
5358
                    friend_user_id = '$userId' AND
5359
                    relation_type = '".USER_RELATION_TYPE_HRM_REQUEST."'
5360
                ";
5361
                break;
5362
        }
5363
5364
        $join = null;
5365
        $sql = " $masterSelect
5366
                (
5367
                    (
5368
                        $select
5369
                        FROM $tbl_user u
5370
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
5371
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
5372
                        $join
5373
                        WHERE
5374
                            access_url_id = ".api_get_current_access_url_id()."
5375
                            $drhConditions
5376
                            $userConditions
5377
                    )
5378
                    $teacherSelect
5379
5380
                ) as t1";
5381
5382
        if ($getSql) {
5383
            return $sql;
5384
        }
5385
        if ($getCount) {
5386
            $result = Database::query($sql);
5387
            $row = Database::fetch_array($result);
5388
5389
            return $row['count'];
5390
        }
5391
5392
        $orderBy = null;
5393
        if ($getOnlyUserId == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
5394
            if (api_is_western_name_order()) {
5395
                $orderBy .= " ORDER BY firstname, lastname ";
5396
            } else {
5397
                $orderBy .= " ORDER BY lastname, firstname ";
5398
            }
5399
5400
            if (!empty($column) && !empty($direction)) {
5401
                // Fixing order due the UNIONs
5402
                $column = str_replace('u.', '', $column);
5403
                $orderBy = " ORDER BY $column $direction ";
5404
            }
5405
        }
5406
5407
        $sql .= $orderBy;
5408
        $sql .= $limitCondition;
5409
5410
        $result = Database::query($sql);
5411
        $users = [];
5412
        if (Database::num_rows($result) > 0) {
5413
            while ($row = Database::fetch_array($result)) {
5414
                $users[$row['user_id']] = $row;
5415
            }
5416
        }
5417
5418
        return $users;
5419
    }
5420
5421
    /**
5422
     * Subscribes users to human resource manager (Dashboard feature).
5423
     *
5424
     * @param int   $hr_dept_id
5425
     * @param array $users_id
5426
     * @param bool  $deleteOtherAssignedUsers
5427
     *
5428
     * @return int
5429
     */
5430
    public static function subscribeUsersToHRManager(
5431
        $hr_dept_id,
5432
        $users_id,
5433
        $deleteOtherAssignedUsers = true
5434
    ) {
5435
        return self::subscribeUsersToUser(
5436
            $hr_dept_id,
5437
            $users_id,
5438
            USER_RELATION_TYPE_RRHH,
5439
            false,
5440
            $deleteOtherAssignedUsers
5441
        );
5442
    }
5443
5444
    /**
5445
     * Register request to assign users to HRM.
5446
     *
5447
     * @param int   $hrmId   The HRM ID
5448
     * @param array $usersId The users IDs
5449
     *
5450
     * @return int
5451
     */
5452
    public static function requestUsersToHRManager($hrmId, $usersId)
5453
    {
5454
        return self::subscribeUsersToUser(
5455
            $hrmId,
5456
            $usersId,
5457
            USER_RELATION_TYPE_HRM_REQUEST,
5458
            false,
5459
            false
5460
        );
5461
    }
5462
5463
    /**
5464
     * Remove the requests for assign a user to a HRM.
5465
     *
5466
     * @param array $usersId List of user IDs from whom to remove all relations requests with HRM
5467
     */
5468
    public static function clearHrmRequestsForUser(User $hrmId, $usersId)
5469
    {
5470
        $users = implode(', ', $usersId);
5471
        Database::getManager()
5472
            ->createQuery('
5473
                DELETE FROM ChamiloCoreBundle:UserRelUser uru
5474
                WHERE uru.friendUserId = :hrm_id AND uru.relationType = :relation_type AND uru.userId IN (:users_ids)
5475
            ')
5476
            ->execute(['hrm_id' => $hrmId, 'relation_type' => USER_RELATION_TYPE_HRM_REQUEST, 'users_ids' => $users]);
5477
    }
5478
5479
    /**
5480
     * Add subscribed users to a user by relation type.
5481
     *
5482
     * @param int    $userId                   The user id
5483
     * @param array  $subscribedUsersId        The id of subscribed users
5484
     * @param string $relationType             The relation type
5485
     * @param bool   $deleteUsersBeforeInsert
5486
     * @param bool   $deleteOtherAssignedUsers
5487
     *
5488
     * @return int
5489
     */
5490
    public static function subscribeUsersToUser(
5491
        $userId,
5492
        $subscribedUsersId,
5493
        $relationType,
5494
        $deleteUsersBeforeInsert = false,
5495
        $deleteOtherAssignedUsers = true
5496
    ) {
5497
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5498
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5499
5500
        $userId = (int) $userId;
5501
        $relationType = (int) $relationType;
5502
        $affectedRows = 0;
5503
5504
        if ($deleteOtherAssignedUsers) {
5505
            if (api_get_multiple_access_url()) {
5506
                // Deleting assigned users to hrm_id
5507
                $sql = "SELECT s.user_id
5508
                        FROM $userRelUserTable s
5509
                        INNER JOIN $userRelAccessUrlTable a
5510
                        ON (a.user_id = s.user_id)
5511
                        WHERE
5512
                            friend_user_id = $userId AND
5513
                            relation_type = $relationType AND
5514
                            access_url_id = ".api_get_current_access_url_id();
5515
            } else {
5516
                $sql = "SELECT user_id
5517
                        FROM $userRelUserTable
5518
                        WHERE
5519
                            friend_user_id = $userId AND
5520
                            relation_type = $relationType";
5521
            }
5522
            $result = Database::query($sql);
5523
5524
            if (Database::num_rows($result) > 0) {
5525
                while ($row = Database::fetch_array($result)) {
5526
                    $sql = "DELETE FROM $userRelUserTable
5527
                            WHERE
5528
                                user_id = {$row['user_id']} AND
5529
                                friend_user_id = $userId AND
5530
                                relation_type = $relationType";
5531
                    Database::query($sql);
5532
                }
5533
            }
5534
        }
5535
5536
        if ($deleteUsersBeforeInsert) {
5537
            $sql = "DELETE FROM $userRelUserTable
5538
                    WHERE
5539
                        user_id = $userId AND
5540
                        relation_type = $relationType";
5541
            Database::query($sql);
5542
        }
5543
5544
        // Inserting new user list
5545
        if (is_array($subscribedUsersId)) {
5546
            foreach ($subscribedUsersId as $subscribedUserId) {
5547
                $subscribedUserId = (int) $subscribedUserId;
5548
                $sql = "SELECT id
5549
                        FROM $userRelUserTable
5550
                        WHERE
5551
                            user_id = $subscribedUserId AND
5552
                            friend_user_id = $userId AND
5553
                            relation_type = $relationType";
5554
5555
                $result = Database::query($sql);
5556
                $num = Database::num_rows($result);
5557
                if ($num === 0) {
5558
                    $date = api_get_utc_datetime();
5559
                    $sql = "INSERT INTO $userRelUserTable (user_id, friend_user_id, relation_type, last_edit)
5560
                            VALUES ($subscribedUserId, $userId, $relationType, '$date')";
5561
                    $result = Database::query($sql);
5562
                    $affectedRows += Database::affected_rows($result);
5563
                }
5564
            }
5565
        }
5566
5567
        return $affectedRows;
5568
    }
5569
5570
    /**
5571
     * This function check if an user is followed by human resources manager.
5572
     *
5573
     * @param int $user_id
5574
     * @param int $hr_dept_id Human resources manager
5575
     *
5576
     * @return bool
5577
     */
5578
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
5579
    {
5580
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5581
        $user_id = (int) $user_id;
5582
        $hr_dept_id = (int) $hr_dept_id;
5583
        $result = false;
5584
5585
        $sql = "SELECT user_id FROM $tbl_user_rel_user
5586
                WHERE
5587
                    user_id = $user_id AND
5588
                    friend_user_id = $hr_dept_id AND
5589
                    relation_type = ".USER_RELATION_TYPE_RRHH;
5590
        $rs = Database::query($sql);
5591
        if (Database::num_rows($rs) > 0) {
5592
            $result = true;
5593
        }
5594
5595
        return $result;
5596
    }
5597
5598
    /**
5599
     * Return the user id of teacher or session administrator.
5600
     *
5601
     * @param array $courseInfo
5602
     *
5603
     * @return mixed The user id, or false if the session ID was negative
5604
     */
5605
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
5606
    {
5607
        $session = api_get_session_id();
5608
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5609
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5610
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5611
5612
        if (empty($courseInfo)) {
5613
            return false;
5614
        }
5615
5616
        $courseId = $courseInfo['real_id'];
5617
5618
        if ($session == 0 || is_null($session)) {
5619
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
5620
                    INNER JOIN '.$table_course_user.' ru
5621
                    ON ru.user_id = u.id
5622
                    WHERE
5623
                        ru.status = 1 AND
5624
                        ru.c_id = "'.$courseId.'" ';
5625
            $rs = Database::query($sql);
5626
            $num_rows = Database::num_rows($rs);
5627
            if ($num_rows == 1) {
5628
                $row = Database::fetch_array($rs);
5629
5630
                return $row['uid'];
5631
            } else {
5632
                $my_num_rows = $num_rows;
5633
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
5634
5635
                return $my_user_id;
5636
            }
5637
        } elseif ($session > 0) {
5638
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
5639
                    INNER JOIN '.$table_session_course_user.' sru
5640
                    ON sru.user_id=u.id
5641
                    WHERE
5642
                        sru.c_id="'.$courseId.'" AND
5643
                        sru.status=2';
5644
            $rs = Database::query($sql);
5645
            $row = Database::fetch_array($rs);
5646
5647
            return $row['uid'];
5648
        }
5649
5650
        return false;
5651
    }
5652
5653
    /**
5654
     * Determines if a user is a gradebook certified.
5655
     *
5656
     * @param int $cat_id  The category id of gradebook
5657
     * @param int $user_id The user id
5658
     *
5659
     * @return bool
5660
     */
5661
    public static function is_user_certified($cat_id, $user_id)
5662
    {
5663
        $cat_id = (int) $cat_id;
5664
        $user_id = (int) $user_id;
5665
5666
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
5667
        $sql = 'SELECT path_certificate
5668
                FROM '.$table.'
5669
                WHERE
5670
                    cat_id = "'.$cat_id.'" AND
5671
                    user_id = "'.$user_id.'"';
5672
        $rs = Database::query($sql);
5673
        $row = Database::fetch_array($rs);
5674
5675
        if ($row['path_certificate'] == '' || is_null($row['path_certificate'])) {
5676
            return false;
5677
        }
5678
5679
        return true;
5680
    }
5681
5682
    /**
5683
     * Gets the info about a gradebook certificate for a user by course.
5684
     *
5685
     * @param string $course_code The course code
5686
     * @param int    $session_id
5687
     * @param int    $user_id     The user id
5688
     *
5689
     * @return array if there is not information return false
5690
     */
5691
    public static function get_info_gradebook_certificate($course_code, $session_id, $user_id)
5692
    {
5693
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
5694
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
5695
        $session_id = (int) $session_id;
5696
        $user_id = (int) $user_id;
5697
5698
        if (empty($session_id)) {
5699
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
5700
        } else {
5701
            $session_condition = " AND session_id = $session_id";
5702
        }
5703
5704
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.'
5705
                WHERE cat_id = (
5706
                    SELECT id FROM '.$tbl_grade_category.'
5707
                    WHERE
5708
                        course_code = "'.Database::escape_string($course_code).'" '.$session_condition.'
5709
                    LIMIT 1
5710
                ) AND user_id='.$user_id;
5711
5712
        $rs = Database::query($sql);
5713
        if (Database::num_rows($rs) > 0) {
5714
            $row = Database::fetch_array($rs, 'ASSOC');
5715
            $score = $row['score_certificate'];
5716
            $category_id = $row['cat_id'];
5717
            $cat = Category::load($category_id);
5718
            $displayscore = ScoreDisplay::instance();
5719
            if (isset($cat) && $displayscore->is_custom()) {
5720
                $grade = $displayscore->display_score(
5721
                    [$score, $cat[0]->get_weight()],
5722
                    SCORE_DIV_PERCENT_WITH_CUSTOM
5723
                );
5724
            } else {
5725
                $grade = $displayscore->display_score(
5726
                    [$score, $cat[0]->get_weight()]
5727
                );
5728
            }
5729
            $row['grade'] = $grade;
5730
5731
            return $row;
5732
        }
5733
5734
        return false;
5735
    }
5736
5737
    /**
5738
     * This function check if the user is a coach inside session course.
5739
     *
5740
     * @param int $user_id    User id
5741
     * @param int $courseId
5742
     * @param int $session_id
5743
     *
5744
     * @return bool True if the user is a coach
5745
     */
5746
    public static function is_session_course_coach($user_id, $courseId, $session_id)
5747
    {
5748
        $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5749
        // Protect data
5750
        $user_id = intval($user_id);
5751
        $courseId = intval($courseId);
5752
        $session_id = intval($session_id);
5753
        $result = false;
5754
5755
        $sql = "SELECT session_id FROM $table
5756
                WHERE
5757
                  session_id = $session_id AND
5758
                  c_id = $courseId AND
5759
                  user_id = $user_id AND
5760
                  status = 2 ";
5761
        $res = Database::query($sql);
5762
5763
        if (Database::num_rows($res) > 0) {
5764
            $result = true;
5765
        }
5766
5767
        return $result;
5768
    }
5769
5770
    /**
5771
     * This function returns an icon path that represents the favicon of the website of which the url given.
5772
     * Defaults to the current Chamilo favicon.
5773
     *
5774
     * @param string $url1 URL of website where to look for favicon.ico
5775
     * @param string $url2 Optional second URL of website where to look for favicon.ico
5776
     *
5777
     * @return string Path of icon to load
5778
     */
5779
    public static function get_favicon_from_url($url1, $url2 = null)
5780
    {
5781
        $icon_link = '';
5782
        $url = $url1;
5783
        if (empty($url1)) {
5784
            $url = $url2;
5785
            if (empty($url)) {
5786
                $url = api_get_access_url(api_get_current_access_url_id());
5787
                $url = $url[0];
5788
            }
5789
        }
5790
        if (!empty($url)) {
5791
            $pieces = parse_url($url);
5792
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
5793
        }
5794
5795
        return $icon_link;
5796
    }
5797
5798
    public static function addUserAsAdmin(User $user)
5799
    {
5800
        if ($user) {
0 ignored issues
show
introduced by
$user is of type Chamilo\UserBundle\Entity\User, thus it always evaluated to true.
Loading history...
5801
            $userId = $user->getId();
5802
            if (!self::is_admin($userId)) {
5803
                $table = Database::get_main_table(TABLE_MAIN_ADMIN);
5804
                $sql = "INSERT INTO $table SET user_id = $userId";
5805
                Database::query($sql);
5806
            }
5807
5808
            $user->addRole('ROLE_SUPER_ADMIN');
5809
            self::getManager()->updateUser($user, true);
5810
        }
5811
    }
5812
5813
    public static function removeUserAdmin(User $user)
5814
    {
5815
        $userId = (int) $user->getId();
5816
        if (self::is_admin($userId)) {
5817
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
5818
            $sql = "DELETE FROM $table WHERE user_id = $userId";
5819
            Database::query($sql);
5820
            $user->removeRole('ROLE_SUPER_ADMIN');
5821
            self::getManager()->updateUser($user, true);
5822
        }
5823
    }
5824
5825
    /**
5826
     * @param string $from
5827
     * @param string $to
5828
     */
5829
    public static function update_all_user_languages($from, $to)
5830
    {
5831
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5832
        $from = Database::escape_string($from);
5833
        $to = Database::escape_string($to);
5834
5835
        if (!empty($to) && !empty($from)) {
5836
            $sql = "UPDATE $table_user SET language = '$to'
5837
                    WHERE language = '$from'";
5838
            Database::query($sql);
5839
        }
5840
    }
5841
5842
    /**
5843
     * Subscribe boss to students.
5844
     *
5845
     * @param int   $bossId                   The boss id
5846
     * @param array $usersId                  The users array
5847
     * @param bool  $deleteOtherAssignedUsers
5848
     *
5849
     * @return int Affected rows
5850
     */
5851
    public static function subscribeBossToUsers($bossId, $usersId, $deleteOtherAssignedUsers = true)
5852
    {
5853
        return self::subscribeUsersToUser(
5854
            $bossId,
5855
            $usersId,
5856
            USER_RELATION_TYPE_BOSS,
5857
            false,
5858
            $deleteOtherAssignedUsers
5859
        );
5860
    }
5861
5862
    /**
5863
     * @param int $userId
5864
     *
5865
     * @return bool
5866
     */
5867
    public static function removeAllBossFromStudent($userId)
5868
    {
5869
        $userId = (int) $userId;
5870
5871
        if (empty($userId)) {
5872
            return false;
5873
        }
5874
5875
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5876
        $sql = "DELETE FROM $userRelUserTable
5877
                WHERE user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
5878
        Database::query($sql);
5879
5880
        return true;
5881
    }
5882
5883
    /**
5884
     * Subscribe boss to students, if $bossList is empty then the boss list will be empty too.
5885
     *
5886
     * @param int   $studentId
5887
     * @param array $bossList
5888
     * @param bool  $sendNotification
5889
     *
5890
     * @return mixed Affected rows or false on failure
5891
     */
5892
    public static function subscribeUserToBossList(
5893
        $studentId,
5894
        $bossList,
5895
        $sendNotification = false
5896
    ) {
5897
        $inserted = 0;
5898
        if (!empty($bossList)) {
5899
            sort($bossList);
5900
            $studentId = (int) $studentId;
5901
            $studentInfo = api_get_user_info($studentId);
5902
5903
            if (empty($studentInfo)) {
5904
                return false;
5905
            }
5906
5907
            $previousBossList = self::getStudentBossList($studentId);
5908
            $previousBossList = !empty($previousBossList) ? array_column($previousBossList, 'boss_id') : [];
5909
            sort($previousBossList);
5910
5911
            // Boss list is the same, nothing changed.
5912
            if ($bossList == $previousBossList) {
5913
                return false;
5914
            }
5915
5916
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5917
            self::removeAllBossFromStudent($studentId);
5918
5919
            foreach ($bossList as $bossId) {
5920
                $bossId = (int) $bossId;
5921
                $bossInfo = api_get_user_info($bossId);
5922
5923
                if (empty($bossInfo)) {
5924
                    continue;
5925
                }
5926
5927
                $bossLanguage = $bossInfo['language'];
5928
5929
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
5930
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
5931
                $insertId = Database::query($sql);
5932
5933
                if ($insertId) {
5934
                    if ($sendNotification) {
5935
                        $name = $studentInfo['complete_name'];
5936
                        $url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$studentId;
5937
                        $url = Display::url($url, $url);
5938
                        $subject = sprintf(
5939
                            get_lang('UserXHasBeenAssignedToBoss', false, $bossLanguage),
5940
                            $name
5941
                        );
5942
                        $message = sprintf(
5943
                            get_lang('UserXHasBeenAssignedToBossWithUrlX', false, $bossLanguage),
5944
                            $name,
5945
                            $url
5946
                        );
5947
                        MessageManager::send_message_simple(
5948
                            $bossId,
5949
                            $subject,
5950
                            $message
5951
                        );
5952
                    }
5953
                    $inserted++;
5954
                }
5955
            }
5956
        } else {
5957
            self::removeAllBossFromStudent($studentId);
5958
        }
5959
5960
        return $inserted;
5961
    }
5962
5963
    /**
5964
     * Get users followed by student boss.
5965
     *
5966
     * @param int    $userId
5967
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
5968
     * @param bool   $getOnlyUserId
5969
     * @param bool   $getSql
5970
     * @param bool   $getCount
5971
     * @param int    $from
5972
     * @param int    $numberItems
5973
     * @param int    $column
5974
     * @param string $direction
5975
     * @param int    $active
5976
     * @param string $lastConnectionDate
5977
     *
5978
     * @return array users
5979
     */
5980
    public static function getUsersFollowedByStudentBoss(
5981
        $userId,
5982
        $userStatus = 0,
5983
        $getOnlyUserId = false,
5984
        $getSql = false,
5985
        $getCount = false,
5986
        $from = null,
5987
        $numberItems = null,
5988
        $column = null,
5989
        $direction = null,
5990
        $active = null,
5991
        $lastConnectionDate = null
5992
    ) {
5993
        return self::getUsersFollowedByUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::getUsersFol...tionDate, STUDENT_BOSS) also could return the type string which is incompatible with the documented return type array.
Loading history...
5994
            $userId,
5995
            $userStatus,
5996
            $getOnlyUserId,
5997
            $getSql,
5998
            $getCount,
5999
            $from,
6000
            $numberItems,
6001
            $column,
6002
            $direction,
6003
            $active,
6004
            $lastConnectionDate,
6005
            STUDENT_BOSS
6006
        );
6007
    }
6008
6009
    /**
6010
     * @return array
6011
     */
6012
    public static function getOfficialCodeGrouped()
6013
    {
6014
        $user = Database::get_main_table(TABLE_MAIN_USER);
6015
        $sql = "SELECT DISTINCT official_code
6016
                FROM $user
6017
                GROUP BY official_code";
6018
        $result = Database::query($sql);
6019
        $values = Database::store_result($result, 'ASSOC');
6020
        $result = [];
6021
        foreach ($values as $value) {
6022
            $result[$value['official_code']] = $value['official_code'];
6023
        }
6024
6025
        return $result;
6026
    }
6027
6028
    /**
6029
     * @param string $officialCode
6030
     *
6031
     * @return array
6032
     */
6033
    public static function getUsersByOfficialCode($officialCode)
6034
    {
6035
        $user = Database::get_main_table(TABLE_MAIN_USER);
6036
        $officialCode = Database::escape_string($officialCode);
6037
6038
        $sql = "SELECT DISTINCT id
6039
                FROM $user
6040
                WHERE official_code = '$officialCode'
6041
                ";
6042
        $result = Database::query($sql);
6043
6044
        $users = [];
6045
        while ($row = Database::fetch_array($result)) {
6046
            $users[] = $row['id'];
6047
        }
6048
6049
        return $users;
6050
    }
6051
6052
    /**
6053
     * Calc the expended time (in seconds) by a user in a course.
6054
     *
6055
     * @param int    $userId    The user id
6056
     * @param int    $courseId  The course id
6057
     * @param int    $sessionId Optional. The session id
6058
     * @param string $from      Optional. From date
6059
     * @param string $until     Optional. Until date
6060
     *
6061
     * @return int The time
6062
     */
6063
    public static function getTimeSpentInCourses(
6064
        $userId,
6065
        $courseId,
6066
        $sessionId = 0,
6067
        $from = '',
6068
        $until = ''
6069
    ) {
6070
        $userId = (int) $userId;
6071
        $sessionId = (int) $sessionId;
6072
6073
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
6074
        $whereConditions = [
6075
            'user_id = ? ' => $userId,
6076
            'AND c_id = ? ' => $courseId,
6077
            'AND session_id = ? ' => $sessionId,
6078
        ];
6079
6080
        if (!empty($from) && !empty($until)) {
6081
            $whereConditions["AND (login_course_date >= '?' "] = $from;
6082
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
6083
        }
6084
6085
        $trackResult = Database::select(
6086
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
6087
            $trackCourseAccessTable,
6088
            [
6089
                'where' => $whereConditions,
6090
            ],
6091
            'first'
6092
        );
6093
6094
        if ($trackResult != false) {
6095
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
6096
        }
6097
6098
        return 0;
6099
    }
6100
6101
    /**
6102
     * Get the boss user ID from a followed user id.
6103
     *
6104
     * @param $userId
6105
     *
6106
     * @return bool
6107
     */
6108
    public static function getFirstStudentBoss($userId)
6109
    {
6110
        $userId = (int) $userId;
6111
        if ($userId > 0) {
6112
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
6113
            $row = Database::select(
6114
                'DISTINCT friend_user_id AS boss_id',
6115
                $userRelTable,
6116
                [
6117
                    'where' => [
6118
                        'user_id = ? AND relation_type = ? LIMIT 1' => [
6119
                            $userId,
6120
                            USER_RELATION_TYPE_BOSS,
6121
                        ],
6122
                    ],
6123
                ]
6124
            );
6125
            if (!empty($row)) {
6126
                return $row[0]['boss_id'];
6127
            }
6128
        }
6129
6130
        return false;
6131
    }
6132
6133
    /**
6134
     * Get the boss user ID from a followed user id.
6135
     *
6136
     * @param int $userId student id
6137
     *
6138
     * @return array
6139
     */
6140
    public static function getStudentBossList($userId)
6141
    {
6142
        $userId = (int) $userId;
6143
6144
        if ($userId > 0) {
6145
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
6146
6147
            return Database::select(
6148
                'DISTINCT friend_user_id AS boss_id',
6149
                $userRelTable,
6150
                [
6151
                    'where' => [
6152
                        'user_id = ? AND relation_type = ? ' => [
6153
                            $userId,
6154
                            USER_RELATION_TYPE_BOSS,
6155
                        ],
6156
                    ],
6157
                ]
6158
            );
6159
        }
6160
6161
        return [];
6162
    }
6163
6164
    /**
6165
     * @param int $bossId
6166
     * @param int $studentId
6167
     *
6168
     * @return bool
6169
     */
6170
    public static function userIsBossOfStudent($bossId, $studentId)
6171
    {
6172
        $result = false;
6173
        $bossList = self::getStudentBossList($studentId);
6174
        if (!empty($bossList)) {
6175
            $bossList = array_column($bossList, 'boss_id');
6176
            if (in_array($bossId, $bossList)) {
6177
                $result = true;
6178
            }
6179
        }
6180
6181
        return $result;
6182
    }
6183
6184
    /**
6185
     * Displays the name of the user and makes the link to the user profile.
6186
     *
6187
     * @param array $userInfo
6188
     *
6189
     * @return string
6190
     */
6191
    public static function getUserProfileLink($userInfo)
6192
    {
6193
        if (isset($userInfo) && isset($userInfo['user_id'])) {
6194
            return Display::url(
6195
                $userInfo['complete_name_with_username'],
6196
                $userInfo['profile_url']
6197
            );
6198
        }
6199
6200
        return get_lang('Anonymous');
6201
    }
6202
6203
    /**
6204
     * Get users whose name matches $firstname and $lastname.
6205
     *
6206
     * @param string $firstname Firstname to search
6207
     * @param string $lastname  Lastname to search
6208
     *
6209
     * @return array The user list
6210
     */
6211
    public static function getUsersByName($firstname, $lastname)
6212
    {
6213
        $firstname = Database::escape_string($firstname);
6214
        $lastname = Database::escape_string($lastname);
6215
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
6216
6217
        $sql = <<<SQL
6218
            SELECT id, username, lastname, firstname
6219
            FROM $userTable
6220
            WHERE
6221
                firstname LIKE '$firstname%' AND
6222
                lastname LIKE '$lastname%'
6223
SQL;
6224
        $result = Database::query($sql);
6225
        $users = [];
6226
        while ($resultData = Database::fetch_object($result)) {
6227
            $users[] = $resultData;
6228
        }
6229
6230
        return $users;
6231
    }
6232
6233
    /**
6234
     * @param int $optionSelected
6235
     *
6236
     * @return string
6237
     */
6238
    public static function getUserSubscriptionTab($optionSelected = 1)
6239
    {
6240
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
6241
        if (($allowAdmin === 'true' && api_is_allowed_to_edit()) ||
6242
            api_is_platform_admin()
6243
        ) {
6244
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
6245
6246
            $headers = [
6247
                [
6248
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
6249
                    'content' => get_lang('Students'),
6250
                ],
6251
                [
6252
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
6253
                    'content' => get_lang('Teachers'),
6254
                ],
6255
                /*[
6256
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
6257
                    'content' => get_lang('Students'),
6258
                ],
6259
                [
6260
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
6261
                    'content' => get_lang('Teachers'),
6262
                ],*/
6263
                [
6264
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
6265
                    'content' => get_lang('Groups'),
6266
                ],
6267
                [
6268
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
6269
                    'content' => get_lang('Classes'),
6270
                ],
6271
            ];
6272
6273
            return Display::tabsOnlyLink($headers, $optionSelected);
6274
        }
6275
6276
        return '';
6277
    }
6278
6279
    /**
6280
     * Make sure this function is protected because it does NOT check password!
6281
     *
6282
     * This function defines globals.
6283
     *
6284
     * @param int  $userId
6285
     * @param bool $checkIfUserCanLoginAs
6286
     *
6287
     * @return bool
6288
     *
6289
     * @author Evie Embrechts
6290
     * @author Yannick Warnier <[email protected]>
6291
     */
6292
    public static function loginAsUser($userId, $checkIfUserCanLoginAs = true)
6293
    {
6294
        $userId = (int) $userId;
6295
        $userInfo = api_get_user_info($userId);
6296
6297
        // Check if the user is allowed to 'login_as'
6298
        $canLoginAs = true;
6299
        if ($checkIfUserCanLoginAs) {
6300
            $canLoginAs = api_can_login_as($userId);
6301
        }
6302
6303
        if (!$canLoginAs || empty($userInfo)) {
6304
            return false;
6305
        }
6306
6307
        if ($userId) {
6308
            $logInfo = [
6309
                'tool' => 'logout',
6310
                'tool_id' => 0,
6311
                'tool_id_detail' => 0,
6312
                'action' => '',
6313
                'info' => 'Change user (login as)',
6314
            ];
6315
            Event::registerLog($logInfo);
0 ignored issues
show
Bug introduced by
The method registerLog() does not exist on Event. ( Ignorable by Annotation )

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

6315
            Event::/** @scrutinizer ignore-call */ 
6316
                   registerLog($logInfo);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
6316
6317
            // Logout the current user
6318
            self::loginDelete(api_get_user_id());
6319
6320
            Session::erase('_user');
6321
            Session::erase('is_platformAdmin');
6322
            Session::erase('is_allowedCreateCourse');
6323
            Session::erase('_uid');
6324
6325
            // Cleaning session variables
6326
            $_user['firstName'] = $userInfo['firstname'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$_user was never initialized. Although not strictly required by PHP, it is generally a good practice to add $_user = array(); before regardless.
Loading history...
6327
            $_user['lastName'] = $userInfo['lastname'];
6328
            $_user['mail'] = $userInfo['email'];
6329
            $_user['official_code'] = $userInfo['official_code'];
6330
            $_user['picture_uri'] = $userInfo['picture_uri'];
6331
            $_user['user_id'] = $userId;
6332
            $_user['id'] = $userId;
6333
            $_user['status'] = $userInfo['status'];
6334
6335
            // Filling session variables with new data
6336
            Session::write('_uid', $userId);
6337
            Session::write('_user', $userInfo);
6338
            Session::write('is_platformAdmin', (bool) self::is_admin($userId));
6339
            Session::write('is_allowedCreateCourse', $userInfo['status'] == 1);
6340
            // will be useful later to know if the user is actually an admin or not (example reporting)
6341
            Session::write('login_as', true);
6342
            $logInfo = [
6343
                'tool' => 'login',
6344
                'tool_id' => 0,
6345
                'tool_id_detail' => 0,
6346
                'info' => $userId,
6347
            ];
6348
            Event::registerLog($logInfo);
6349
6350
            return true;
6351
        }
6352
6353
        return false;
6354
    }
6355
6356
    /**
6357
     * Remove all login records from the track_e_online stats table,
6358
     * for the given user ID.
6359
     *
6360
     * @param int $userId User ID
6361
     */
6362
    public static function loginDelete($userId)
6363
    {
6364
        $online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
6365
        $userId = (int) $userId;
6366
        $query = "DELETE FROM $online_table WHERE login_user_id = $userId";
6367
        Database::query($query);
6368
    }
6369
6370
    /**
6371
     * Login as first admin user registered in the platform.
6372
     *
6373
     * @return array
6374
     */
6375
    public static function logInAsFirstAdmin()
6376
    {
6377
        $adminList = self::get_all_administrators();
6378
6379
        if (!empty($adminList)) {
6380
            $userInfo = current($adminList);
6381
            if (!empty($userInfo)) {
6382
                $result = self::loginAsUser($userInfo['user_id'], false);
6383
                if ($result && api_is_platform_admin()) {
6384
                    return api_get_user_info();
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_user_info() could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
6385
                }
6386
            }
6387
        }
6388
6389
        return [];
6390
    }
6391
6392
    /**
6393
     * Check if user is teacher of a student based in their courses.
6394
     *
6395
     * @param $teacherId
6396
     * @param $studentId
6397
     *
6398
     * @return array
6399
     */
6400
    public static function getCommonCoursesBetweenTeacherAndStudent($teacherId, $studentId)
6401
    {
6402
        $courses = CourseManager::getCoursesFollowedByUser(
6403
            $teacherId,
6404
            COURSEMANAGER
6405
        );
6406
        if (empty($courses)) {
6407
            return false;
6408
        }
6409
6410
        $coursesFromUser = CourseManager::get_courses_list_by_user_id($studentId);
6411
        if (empty($coursesFromUser)) {
6412
            return false;
6413
        }
6414
6415
        $coursesCodeList = array_column($courses, 'code');
6416
        $coursesCodeFromUserList = array_column($coursesFromUser, 'code');
6417
        $commonCourses = array_intersect($coursesCodeList, $coursesCodeFromUserList);
6418
        $commonCourses = array_filter($commonCourses);
6419
6420
        if (!empty($commonCourses)) {
6421
            return $commonCourses;
6422
        }
6423
6424
        return [];
6425
    }
6426
6427
    /**
6428
     * @param int $teacherId
6429
     * @param int $studentId
6430
     *
6431
     * @return bool
6432
     */
6433
    public static function isTeacherOfStudent($teacherId, $studentId)
6434
    {
6435
        $courses = self::getCommonCoursesBetweenTeacherAndStudent(
6436
            $teacherId,
6437
            $studentId
6438
        );
6439
6440
        if (!empty($courses)) {
6441
            return true;
6442
        }
6443
6444
        return false;
6445
    }
6446
6447
    /**
6448
     * Send user confirmation mail.
6449
     *
6450
     * @throws Exception
6451
     */
6452
    public static function sendUserConfirmationMail(User $user)
6453
    {
6454
        $uniqueId = api_get_unique_id();
6455
        $user->setConfirmationToken($uniqueId);
6456
6457
        Database::getManager()->persist($user);
6458
        Database::getManager()->flush();
6459
6460
        $url = api_get_path(WEB_CODE_PATH).'auth/user_mail_confirmation.php?token='.$uniqueId;
6461
6462
        // Check if the user was originally set for an automated subscription to a course or session
6463
        $courseCodeToRedirect = Session::read('course_redirect');
6464
        $sessionToRedirect = Session::read('session_redirect');
6465
        if (!empty($courseCodeToRedirect)) {
6466
            $url .= '&c='.$courseCodeToRedirect;
6467
        }
6468
        if (!empty($sessionToRedirect)) {
6469
            $url .= '&s='.$sessionToRedirect;
6470
        }
6471
        $mailSubject = get_lang('RegistrationConfirmation');
6472
        $mailBody = get_lang('RegistrationConfirmationEmailMessage')
6473
            .PHP_EOL
6474
            .Display::url($url, $url);
6475
6476
        api_mail_html(
6477
            self::formatUserFullName($user),
6478
            $user->getEmail(),
6479
            $mailSubject,
6480
            $mailBody
6481
        );
6482
        Display::addFlash(Display::return_message(get_lang('CheckYourEmailAndFollowInstructions')));
6483
    }
6484
6485
    /**
6486
     * Anonymize a user. Replace personal info by anonymous info.
6487
     *
6488
     * @param int  $userId   User id
6489
     * @param bool $deleteIP Whether to replace the IP address in logs tables by 127.0.0.1 or to leave as is
6490
     *
6491
     * @throws \Exception
6492
     *
6493
     * @return bool
6494
     * @assert (0) === false
6495
     */
6496
    public static function anonymize($userId, $deleteIP = true)
6497
    {
6498
        global $debug;
6499
6500
        $userId = (int) $userId;
6501
6502
        if (empty($userId)) {
6503
            return false;
6504
        }
6505
6506
        $em = Database::getManager();
6507
        $user = api_get_user_entity($userId);
6508
        $uniqueId = uniqid('anon', true);
6509
        $user
6510
            ->setFirstname($uniqueId)
6511
            ->setLastname($uniqueId)
6512
            ->setBiography('')
6513
            ->setAddress('')
6514
            ->setCurriculumItems(null)
6515
            ->setDateOfBirth(null)
6516
            ->setCompetences('')
6517
            ->setDiplomas('')
6518
            ->setOpenarea('')
6519
            ->setTeach('')
6520
            ->setProductions(null)
6521
            ->setOpenid('')
6522
            ->setEmailCanonical($uniqueId.'@example.com')
6523
            ->setEmail($uniqueId.'@example.com')
6524
            ->setUsername($uniqueId)
6525
            ->setUsernameCanonical($uniqueId)
6526
            ->setPhone('')
6527
            ->setOfficialCode('')
6528
        ;
6529
6530
        self::deleteUserPicture($userId);
6531
        self::cleanUserRequestsOfRemoval($userId);
6532
6533
        // The IP address is a border-case personal data, as it does
6534
        // not directly allow for personal identification (it is not
6535
        // a completely safe value in most countries - the IP could
6536
        // be used by neighbours and crackers)
6537
        if ($deleteIP) {
6538
            $substitute = '127.0.0.1';
6539
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
6540
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE access_user_id = $userId";
6541
            $res = Database::query($sql);
6542
            if ($res === false && $debug > 0) {
6543
                error_log("Could not anonymize IP address for user $userId ($sql)");
6544
            }
6545
6546
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
6547
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
6548
            $res = Database::query($sql);
6549
            if ($res === false && $debug > 0) {
6550
                error_log("Could not anonymize IP address for user $userId ($sql)");
6551
            }
6552
6553
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
6554
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE exe_user_id = $userId";
6555
            $res = Database::query($sql);
6556
            if ($res === false && $debug > 0) {
6557
                error_log("Could not anonymize IP address for user $userId ($sql)");
6558
            }
6559
6560
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
6561
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE login_user_id = $userId";
6562
            $res = Database::query($sql);
6563
            if ($res === false && $debug > 0) {
6564
                error_log("Could not anonymize IP address for user $userId ($sql)");
6565
            }
6566
6567
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
6568
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE login_user_id = $userId";
6569
            $res = Database::query($sql);
6570
            if ($res === false && $debug > 0) {
6571
                error_log("Could not anonymize IP address for user $userId ($sql)");
6572
            }
6573
6574
            $table = Database::get_course_table(TABLE_WIKI);
6575
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
6576
            $res = Database::query($sql);
6577
            if ($res === false && $debug > 0) {
6578
                error_log("Could not anonymize IP address for user $userId ($sql)");
6579
            }
6580
6581
            $table = Database::get_main_table(TABLE_TICKET_MESSAGE);
6582
            $sql = "UPDATE $table set ip_address = '$substitute' WHERE sys_insert_user_id = $userId";
6583
            $res = Database::query($sql);
6584
            if ($res === false && $debug > 0) {
6585
                error_log("Could not anonymize IP address for user $userId ($sql)");
6586
            }
6587
6588
            $table = Database::get_course_table(TABLE_WIKI);
6589
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
6590
            $res = Database::query($sql);
6591
            if ($res === false && $debug > 0) {
6592
                error_log("Could not anonymize IP address for user $userId ($sql)");
6593
            }
6594
        }
6595
        $em->persist($user);
6596
        $em->flush($user);
6597
        Event::addEvent(LOG_USER_ANONYMIZE, LOG_USER_ID, $userId);
6598
6599
        return true;
6600
    }
6601
6602
    /**
6603
     * @param int $userId
6604
     *
6605
     * @throws Exception
6606
     *
6607
     * @return string
6608
     */
6609
    public static function anonymizeUserWithVerification($userId)
6610
    {
6611
        $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
6612
6613
        $message = '';
6614
        if (api_is_platform_admin() ||
6615
            ($allowDelete && api_is_session_admin())
6616
        ) {
6617
            $userToUpdateInfo = api_get_user_info($userId);
6618
            $currentUserId = api_get_user_id();
6619
6620
            if ($userToUpdateInfo &&
6621
                api_global_admin_can_edit_admin($userId, null, $allowDelete)
6622
            ) {
6623
                if ($userId != $currentUserId &&
6624
                    self::anonymize($userId)
6625
                ) {
6626
                    $message = Display::return_message(
6627
                        sprintf(get_lang('UserXAnonymized'), $userToUpdateInfo['complete_name_with_username']),
6628
                        'confirmation'
6629
                    );
6630
                } else {
6631
                    $message = Display::return_message(
6632
                        sprintf(get_lang('CannotAnonymizeUserX'), $userToUpdateInfo['complete_name_with_username']),
6633
                        'error'
6634
                    );
6635
                }
6636
            } else {
6637
                $message = Display::return_message(
6638
                    sprintf(get_lang('NoPermissionToAnonymizeUserX'), $userToUpdateInfo['complete_name_with_username']),
6639
                    'error'
6640
                );
6641
            }
6642
        }
6643
6644
        return $message;
6645
    }
6646
6647
    /**
6648
     * @param int $userId
6649
     *
6650
     * @throws Exception
6651
     *
6652
     * @return string
6653
     */
6654
    public static function deleteUserWithVerification($userId)
6655
    {
6656
        $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
6657
        $message = Display::return_message(get_lang('CannotDeleteUser'), 'error');
6658
        $userToUpdateInfo = api_get_user_info($userId);
6659
6660
        // User must exist.
6661
        if (empty($userToUpdateInfo)) {
6662
            return $message;
6663
        }
6664
6665
        $currentUserId = api_get_user_id();
6666
6667
        // Cannot delete myself.
6668
        if ($userId == $currentUserId) {
6669
            return $message;
6670
        }
6671
6672
        if (api_is_platform_admin() ||
6673
            ($allowDelete && api_is_session_admin())
6674
        ) {
6675
            if (api_global_admin_can_edit_admin($userId, null, $allowDelete)) {
6676
                if (self::delete_user($userId)) {
6677
                    $message = Display::return_message(
6678
                        get_lang('UserDeleted').': '.$userToUpdateInfo['complete_name_with_username'],
6679
                        'confirmation'
6680
                    );
6681
                } else {
6682
                    $message = Display::return_message(get_lang('CannotDeleteUserBecauseOwnsCourse'), 'error');
6683
                }
6684
            }
6685
        }
6686
6687
        return $message;
6688
    }
6689
6690
    /**
6691
     * @return array
6692
     */
6693
    public static function createDataPrivacyExtraFields()
6694
    {
6695
        self::create_extra_field(
6696
            'request_for_legal_agreement_consent_removal_justification',
6697
            1, //text
6698
            'Request for legal agreement consent removal justification	',
6699
            ''
6700
        );
6701
6702
        self::create_extra_field(
6703
            'request_for_delete_account_justification',
6704
            1, //text
6705
            'Request for delete account justification',
6706
            ''
6707
        );
6708
6709
        $extraFieldId = self::create_extra_field(
6710
            'request_for_legal_agreement_consent_removal',
6711
            1, //text
6712
            'Request for legal agreement consent removal',
6713
            ''
6714
        );
6715
6716
        $extraFieldIdDeleteAccount = self::create_extra_field(
6717
            'request_for_delete_account',
6718
            1, //text
6719
            'Request for delete user account',
6720
            ''
6721
        );
6722
6723
        return [
6724
            'delete_account_extra_field' => $extraFieldIdDeleteAccount,
6725
            'delete_legal' => $extraFieldId,
6726
        ];
6727
    }
6728
6729
    /**
6730
     * @param int $userId
6731
     */
6732
    public static function cleanUserRequestsOfRemoval($userId)
6733
    {
6734
        $userId = (int) $userId;
6735
6736
        $extraFieldValue = new ExtraFieldValue('user');
6737
        $extraFieldsToDelete = [
6738
            'legal_accept',
6739
            'request_for_legal_agreement_consent_removal',
6740
            'request_for_legal_agreement_consent_removal_justification',
6741
            'request_for_delete_account_justification', // just in case delete also this
6742
            'request_for_delete_account',
6743
        ];
6744
6745
        foreach ($extraFieldsToDelete as $variable) {
6746
            $value = $extraFieldValue->get_values_by_handler_and_field_variable(
6747
                $userId,
6748
                $variable
6749
            );
6750
            if ($value && isset($value['id'])) {
6751
                $extraFieldValue->delete($value['id']);
6752
            }
6753
        }
6754
    }
6755
6756
    /**
6757
     * @param int $searchYear
6758
     *
6759
     * @throws Exception
6760
     *
6761
     * @return array
6762
     */
6763
    public static function getSubscribedSessionsByYear(array $userInfo, $searchYear)
6764
    {
6765
        $timezone = new DateTimeZone(api_get_timezone());
6766
6767
        $sessions = [];
6768
        if (DRH == $userInfo['status']) {
6769
            $sessions = SessionManager::get_sessions_followed_by_drh($userInfo['id']);
6770
        } elseif (api_is_platform_admin(true)) {
6771
            $sessions = SessionManager::getSessionsForAdmin($userInfo['id']);
6772
        } else {
6773
            $sessionsByCategory = self::get_sessions_by_category($userInfo['id'], false, true, true);
6774
            $sessionsByCategory = array_column($sessionsByCategory, 'sessions');
6775
6776
            foreach ($sessionsByCategory as $sessionsInCategory) {
6777
                $sessions = array_merge($sessions, $sessionsInCategory);
6778
            }
6779
        }
6780
6781
        $sessions = array_map(
6782
            function ($sessionInfo) {
6783
                if (!isset($sessionInfo['session_id'])) {
6784
                    $sessionInfo['session_id'] = $sessionInfo['id'];
6785
                }
6786
                if (!isset($sessionInfo['session_name'])) {
6787
                    $sessionInfo['session_name'] = $sessionInfo['name'];
6788
                }
6789
6790
                return $sessionInfo;
6791
            },
6792
            $sessions
6793
        );
6794
6795
        $calendarSessions = [];
6796
6797
        foreach ($sessions as $sessionInfo) {
6798
            if (!empty($sessionInfo['duration'])) {
6799
                $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser(
6800
                    $sessionInfo['session_id'],
6801
                    $userInfo['id']
6802
                );
6803
6804
                if (empty($courseAccess)) {
6805
                    continue;
6806
                }
6807
6808
                $firstAcessDate = new DateTime(api_get_local_time($courseAccess['login_course_date']), $timezone);
6809
                $lastAccessDate = clone $firstAcessDate;
6810
                $lastAccessDate->modify("+{$sessionInfo['duration']} days");
6811
6812
                $firstAccessYear = (int) $firstAcessDate->format('Y');
6813
                $lastAccessYear = (int) $lastAccessDate->format('Y');
6814
6815
                if ($firstAccessYear <= $searchYear && $lastAccessYear >= $searchYear) {
6816
                    $calendarSessions[$sessionInfo['session_id']] = [
6817
                        'name' => $sessionInfo['session_name'],
6818
                        'access_start_date' => $firstAcessDate->format('Y-m-d h:i:s'),
6819
                        'access_end_date' => $lastAccessDate->format('Y-m-d h:i:s'),
6820
                    ];
6821
                }
6822
6823
                continue;
6824
            }
6825
6826
            $accessStartDate = !empty($sessionInfo['access_start_date'])
6827
                ? new DateTime(api_get_local_time($sessionInfo['access_start_date']), $timezone)
6828
                : null;
6829
            $accessEndDate = !empty($sessionInfo['access_end_date'])
6830
                ? new DateTime(api_get_local_time($sessionInfo['access_end_date']), $timezone)
6831
                : null;
6832
            $accessStartYear = $accessStartDate ? (int) $accessStartDate->format('Y') : 0;
6833
            $accessEndYear = $accessEndDate ? (int) $accessEndDate->format('Y') : 0;
6834
6835
            $isValid = false;
6836
6837
            if ($accessStartYear && $accessEndYear) {
6838
                if ($accessStartYear <= $searchYear && $accessEndYear >= $searchYear) {
6839
                    $isValid = true;
6840
                }
6841
            }
6842
6843
            if ($accessStartYear && !$accessEndYear) {
6844
                if ($accessStartYear == $searchYear) {
6845
                    $isValid = true;
6846
                }
6847
            }
6848
6849
            if (!$accessStartYear && $accessEndYear) {
6850
                if ($accessEndYear == $searchYear) {
6851
                    $isValid = true;
6852
                }
6853
            }
6854
6855
            if ($isValid) {
6856
                $calendarSessions[$sessionInfo['session_id']] = [
6857
                    'name' => $sessionInfo['session_name'],
6858
                    'access_start_date' => $accessStartDate ? $accessStartDate->format('Y-m-d h:i:s') : null,
6859
                    'access_end_date' => $accessEndDate ? $accessEndDate->format('Y-m-d h:i:s') : null,
6860
                ];
6861
            }
6862
        }
6863
6864
        return $calendarSessions;
6865
    }
6866
6867
    /**
6868
     * Get sessions info for planification calendar.
6869
     *
6870
     * @param array $sessionsList Session list from UserManager::getSubscribedSessionsByYear
6871
     * @param int   $searchYear
6872
     *
6873
     * @throws Exception
6874
     *
6875
     * @return array
6876
     */
6877
    public static function getSessionsCalendarByYear(array $sessionsList, $searchYear)
6878
    {
6879
        $timezone = new DateTimeZone(api_get_timezone());
6880
        $calendar = [];
6881
6882
        foreach ($sessionsList as $sessionId => $sessionInfo) {
6883
            $startDate = $sessionInfo['access_start_date']
6884
                ? new DateTime(api_get_local_time($sessionInfo['access_start_date']), $timezone)
6885
                : null;
6886
            $endDate = $sessionInfo['access_end_date']
6887
                ? new DateTime(api_get_local_time($sessionInfo['access_end_date']), $timezone)
6888
                : null;
6889
6890
            $startYear = $startDate ? (int) $startDate->format('Y') : 0;
6891
            $startWeekYear = $startDate ? (int) $startDate->format('o') : 0;
6892
            $startWeek = $startDate ? (int) $startDate->format('W') : 0;
6893
            $endYear = $endDate ? (int) $endDate->format('Y') : 0;
6894
            $endWeekYear = $endDate ? (int) $endDate->format('o') : 0;
6895
            $endWeek = $endDate ? (int) $endDate->format('W') : 0;
6896
6897
            $start = $startWeekYear < $searchYear ? 0 : $startWeek - 1;
6898
            $duration = $endWeekYear > $searchYear ? 52 - $start : $endWeek - $start;
6899
6900
            $calendar[] = [
6901
                'id' => $sessionId,
6902
                'name' => $sessionInfo['name'],
6903
                'human_date' => SessionManager::convertSessionDateToString($startDate, $endDate, false, true),
6904
                'start_in_last_year' => $startYear < $searchYear,
6905
                'end_in_next_year' => $endYear > $searchYear,
6906
                'no_start' => !$startWeek,
6907
                'no_end' => !$endWeek,
6908
                'start' => $start,
6909
                'duration' => $duration > 0 ? $duration : 1,
6910
            ];
6911
        }
6912
6913
        usort(
6914
            $calendar,
6915
            function ($sA, $sB) {
6916
                if ($sA['start'] == $sB['start']) {
6917
                    return 0;
6918
                }
6919
6920
                if ($sA['start'] < $sB['start']) {
6921
                    return -1;
6922
                }
6923
6924
                return 1;
6925
            }
6926
        );
6927
6928
        return $calendar;
6929
    }
6930
6931
    /**
6932
     * Return the user's full name. Optionally with the username.
6933
     *
6934
     * @param bool $includeUsername Optional. By default username is not included.
6935
     *
6936
     * @return string
6937
     */
6938
    public static function formatUserFullName(User $user, $includeUsername = false)
6939
    {
6940
        $fullName = api_get_person_name($user->getFirstname(), $user->getLastname());
6941
6942
        if ($includeUsername && api_get_configuration_value('hide_username_with_complete_name') !== true) {
6943
            $username = $user->getUsername();
6944
6945
            return "$fullName ($username)";
6946
        }
6947
6948
        return $fullName;
6949
    }
6950
6951
    /**
6952
     * @param int $userId
6953
     *
6954
     * @return array
6955
     */
6956
    public static function getUserCareers($userId)
6957
    {
6958
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6959
        $tableCareer = Database::get_main_table(TABLE_CAREER);
6960
        $userId = (int) $userId;
6961
6962
        $sql = "SELECT c.id, c.name
6963
                FROM $table uc
6964
                INNER JOIN $tableCareer c
6965
                ON uc.career_id = c.id
6966
                WHERE user_id = $userId
6967
                ORDER BY uc.created_at
6968
                ";
6969
        $result = Database::query($sql);
6970
6971
        return Database::store_result($result, 'ASSOC');
6972
    }
6973
6974
    /**
6975
     * @param int $userId
6976
     * @param int $careerId
6977
     */
6978
    public static function addUserCareer($userId, $careerId)
6979
    {
6980
        if (!api_get_configuration_value('allow_career_users')) {
6981
            return false;
6982
        }
6983
6984
        if (self::userHasCareer($userId, $careerId) === false) {
6985
            $params = ['user_id' => $userId, 'career_id' => $careerId, 'created_at' => api_get_utc_datetime(), 'updated_at' => api_get_utc_datetime()];
6986
            $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6987
            Database::insert($table, $params);
6988
        }
6989
6990
        return true;
6991
    }
6992
6993
    /**
6994
     * @param int   $userCareerId
6995
     * @param array $data
6996
     *
6997
     * @return bool
6998
     */
6999
    public static function updateUserCareer($userCareerId, $data)
7000
    {
7001
        if (!api_get_configuration_value('allow_career_users')) {
7002
            return false;
7003
        }
7004
7005
        $params = ['extra_data' => $data, 'updated_at' => api_get_utc_datetime()];
7006
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
7007
        Database::update(
7008
            $table,
7009
            $params,
7010
            ['id = ?' => (int) $userCareerId]
7011
        );
7012
7013
        return true;
7014
    }
7015
7016
    /**
7017
     * @param int $userId
7018
     * @param int $careerId
7019
     *
7020
     * @return array
7021
     */
7022
    public static function getUserCareer($userId, $careerId)
7023
    {
7024
        $userId = (int) $userId;
7025
        $careerId = (int) $careerId;
7026
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
7027
7028
        $sql = "SELECT * FROM $table WHERE user_id = $userId AND career_id = $careerId";
7029
        $result = Database::query($sql);
7030
7031
        return Database::fetch_array($result, 'ASSOC');
7032
    }
7033
7034
    /**
7035
     * @param int $userId
7036
     * @param int $careerId
7037
     *
7038
     * @return bool
7039
     */
7040
    public static function userHasCareer($userId, $careerId)
7041
    {
7042
        $userId = (int) $userId;
7043
        $careerId = (int) $careerId;
7044
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
7045
7046
        $sql = "SELECT id FROM $table WHERE user_id = $userId AND career_id = $careerId";
7047
        $result = Database::query($sql);
7048
7049
        return Database::num_rows($result) > 0;
7050
    }
7051
7052
    /**
7053
     * @param int $userInfo
7054
     *
7055
     * @throws Exception
7056
     */
7057
    public static function deleteUserFiles($userId)
7058
    {
7059
        $path = self::getUserPathById($userId, 'system');
7060
7061
        $fs = new Filesystem();
7062
        $fs->remove($path);
7063
    }
7064
7065
    /**
7066
     * @return EncoderFactory
7067
     */
7068
    private static function getEncoderFactory()
7069
    {
7070
        $encryption = self::getPasswordEncryption();
7071
        $encoders = [
7072
            'Chamilo\\UserBundle\\Entity\\User' => new \Chamilo\UserBundle\Security\Encoder($encryption),
7073
        ];
7074
7075
        return new EncoderFactory($encoders);
7076
    }
7077
7078
    /**
7079
     * @return \Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface
7080
     */
7081
    private static function getEncoder(User $user)
7082
    {
7083
        $encoderFactory = self::getEncoderFactory();
7084
7085
        return $encoderFactory->getEncoder($user);
7086
    }
7087
7088
    /**
7089
     * Disables or enables a user.
7090
     *
7091
     * @param int $user_id
7092
     * @param int $active  Enable or disable
7093
     *
7094
     * @return bool True on success, false on failure
7095
     * @assert (-1,0) === false
7096
     * @assert (1,1) === true
7097
     */
7098
    private static function change_active_state($user_id, $active)
7099
    {
7100
        $user_id = (int) $user_id;
7101
        $active = (int) $active;
7102
7103
        if (empty($user_id)) {
7104
            return false;
7105
        }
7106
7107
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7108
        $sql = "UPDATE $table_user SET active = '$active' WHERE id = $user_id";
7109
        $r = Database::query($sql);
7110
        $ev = LOG_USER_DISABLE;
7111
        if ($active == 1) {
7112
            $ev = LOG_USER_ENABLE;
7113
        }
7114
        if ($r !== false) {
7115
            Event::addEvent($ev, LOG_USER_ID, $user_id);
7116
        }
7117
7118
        return $r;
7119
    }
7120
7121
    /**
7122
     * Get either a Gravatar URL or complete image tag for a specified email address.
7123
     *
7124
     * @param string $email The email address
7125
     * @param int    $s     Size in pixels, defaults to 80px [ 1 - 2048 ]
7126
     * @param string $d     Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
7127
     * @param string $r     Maximum rating (inclusive) [ g | pg | r | x ]
7128
     * @param bool   $img   True to return a complete IMG tag False for just the URL
7129
     * @param array  $atts  Optional, additional key/value attributes to include in the IMG tag
7130
     *
7131
     * @return string containing either just a URL or a complete image tag
7132
     * @source http://gravatar.com/site/implement/images/php/
7133
     */
7134
    private static function getGravatar(
7135
        $email,
7136
        $s = 80,
7137
        $d = 'mm',
7138
        $r = 'g',
7139
        $img = false,
7140
        $atts = []
7141
    ) {
7142
        $url = 'http://www.gravatar.com/avatar/';
7143
        if (!empty($_SERVER['HTTPS'])) {
7144
            $url = 'https://secure.gravatar.com/avatar/';
7145
        }
7146
        $url .= md5(strtolower(trim($email)));
7147
        $url .= "?s=$s&d=$d&r=$r";
7148
        if ($img) {
7149
            $url = '<img src="'.$url.'"';
7150
            foreach ($atts as $key => $val) {
7151
                $url .= ' '.$key.'="'.$val.'"';
7152
            }
7153
            $url .= ' />';
7154
        }
7155
7156
        return $url;
7157
    }
7158
7159
    private static function checkEmail($email)
0 ignored issues
show
Unused Code introduced by
The method checkEmail() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
7160
    {
7161
7162
    }
7163
}
7164