Test Setup Failed
Push — master ( f71949...6c6bd7 )
by Julito
55:21
created

UserManager::add_user_as_admin()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
5
use Chamilo\UserBundle\Entity\User;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\CoreBundle\Entity\AccessUrlRelUser;
8
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder;
9
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
10
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
11
use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder;
12
13
/**
14
 *
15
 * Class UserManager
16
 *
17
 * This library provides functions for user management.
18
 * Include/require it in your code to use its functionality.
19
 * @package chamilo.library
20
 * @author Julio Montoya <[email protected]> Social network groups added 2009/12
21
 *
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
     * @assert () === null
46
     */
47
    public function __construct()
48
    {
49
    }
50
51
    /**
52
     * Repository is use to query the DB, selects, etc
53
     * @return Chamilo\UserBundle\Entity\Repository\UserRepository
54
     */
55
    public static function getRepository()
56
    {
57
        return Database::getManager()->getRepository('ChamiloUserBundle:User');
58
    }
59
60
    /**
61
     * Create/update/delete methods are available in the UserManager
62
     * (based in the Sonata\UserBundle\Entity\UserManager)
63
     *
64
     * @return Chamilo\UserBundle\Entity\Manager\UserManager
65
     */
66
    public static function getManager()
67
    {
68
        return Container::getUserManager();
69
    }
70
71
    /**
72
     * @param string $encryptionMethod
73
     */
74
    public static function setPasswordEncryption($encryptionMethod)
75
    {
76
        self::$encryptionMethod = $encryptionMethod;
77
    }
78
79
    /**
80
     * @return bool|mixed
81
     */
82
    public static function getPasswordEncryption()
83
    {
84
        $encryptionMethod = self::$encryptionMethod;
85
        if (empty($encryptionMethod)) {
86
            $encryptionMethod = api_get_configuration_value('password_encryption');
87
        }
88
89
        return $encryptionMethod;
90
    }
91
92
    /**
93
     * @return EncoderFactory
94
     */
95
    private static function getEncoderFactory()
96
    {
97
        $encryption = self::getPasswordEncryption();
98
        $encoders = array(
99
            'Chamilo\\UserBundle\\Entity\\User' => new \Chamilo\UserBundle\Security\Encoder($encryption)
100
        );
101
102
        $encoderFactory = new EncoderFactory($encoders);
103
104
        return $encoderFactory;
105
    }
106
107
    /**
108
     * @param User $user
109
     *
110
     * @return \Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface
111
     */
112
    private static function getEncoder(User $user)
113
    {
114
        $encoderFactory = self::getEncoderFactory();
115
116
        return $encoderFactory->getEncoder($user);
117
    }
118
119
    /**
120
     * Validates the password
121
     *
122
     * @param $encoded
123
     * @param $raw
124
     * @param $salt
125
     * @return bool
126
     */
127
    public static function isPasswordValid($encoded, $raw, $salt)
128
    {
129
        $encoder = new \Chamilo\UserBundle\Security\Encoder(self::getPasswordEncryption());
130
        $validPassword = $encoder->isPasswordValid($encoded, $raw, $salt);
131
132
        return $validPassword;
133
    }
134
135
    /**
136
     * @param string $raw
137
     * @param User   $user
138
     *
139
     * @return bool
140
     */
141
    public static function encryptPassword($raw, User $user)
142
    {
143
        $encoder = self::getEncoder($user);
144
145
        $encodedPassword = $encoder->encodePassword(
146
            $raw,
147
            $user->getSalt()
148
        );
149
150
        return $encodedPassword;
151
    }
152
153
    /**
154
     * @param int $userId
155
     * @param string $password
156
     *
157
     */
158
    public static function updatePassword($userId, $password)
159
    {
160
        $repository = self::getRepository();
161
        /** @var User $user */
162
        $user = $repository->find($userId);
163
        $userManager = self::getManager();
164
        $user->setPlainPassword($password);
165
        $userManager->updateUser($user, true);
166
    }
167
168
    /**
169
     * Creates a new user for the platform
170
     * @author Hugues Peeters <[email protected]>,
171
     * @author Roan Embrechts <[email protected]>
172
     * @param  string $firstName
173
     * @param  string $lastName
174
     * @param  int    $status (1 for course tutor, 5 for student, 6 for anonymous)
175
     * @param  string $email
176
     * @param  string $loginName
177
     * @param  string $password
178
     * @param  string $official_code Any official code (optional)
179
     * @param  string $language User language    (optional)
180
     * @param  string $phone Phone number    (optional)
181
     * @param  string $picture_uri Picture URI        (optional)
182
     * @param  string $authSource Authentication source    (optional, defaults to 'platform', dependind on constant)
183
     * @param  string $expirationDate Account expiration date (optional, defaults to null)
184
     * @param  int    $active Whether the account is enabled or disabled by default
185
     * @param  int    $hr_dept_id The department of HR in which the user is registered (optional, defaults to 0)
186
     * @param  array  $extra    Extra fields
187
     * @param  string $encrypt_method Encrypt method used if password is given encrypted. Set to an empty string by default
188
     * @param  bool $send_mail
189
     * @param  bool $isAdmin
190
     * @param  string $address
191
     * @param  bool $sendEmailToAllAdmins
192
     * @param FormValidator $form
193
     *
194
     * @return mixed   new user id - if the new user creation succeeds, false otherwise
195
     * @desc The function tries to retrieve user id from the session.
196
     * If it exists, the current user id is the creator id. If a problem arises,
197
     * @assert ('Sam','Gamegie',5,'[email protected]','jo','jo') > 1
198
     * @assert ('Pippin','Took',null,null,'jo','jo') === false
199
     */
200
    public static function create_user(
201
        $firstName,
202
        $lastName,
203
        $status,
204
        $email,
205
        $loginName,
206
        $password,
207
        $official_code = '',
208
        $language = '',
209
        $phone = '',
210
        $picture_uri = '',
211
        $authSource = PLATFORM_AUTH_SOURCE,
212
        $expirationDate = null,
213
        $active = 1,
214
        $hr_dept_id = 0,
215
        $extra = [],
216
        $encrypt_method = '',
217
        $send_mail = false,
218
        $isAdmin = false,
219
        $address = '',
220
        $sendEmailToAllAdmins = false,
221
        $form = null
222
    ) {
223
        $currentUserId = api_get_user_id();
224
        $hook = HookCreateUser::create();
225
        if (!empty($hook)) {
226
            $hook->notifyCreateUser(HOOK_EVENT_TYPE_PRE);
227
        }
228
229
        // First check wether the login already exists
230
        if (!self::is_username_available($loginName)) {
231
            Display::addFlash(
232
                Display::return_message(get_lang('LoginAlreadyTaken'))
233
            );
234
235
            return false;
236
        }
237
238
        global $_configuration;
239
        $original_password = $password;
240
241
        $access_url_id = 1;
242
        if (api_get_multiple_access_url()) {
243
            $access_url_id = api_get_current_access_url_id();
244
        }
245
246 View Code Duplication
        if (isset($_configuration[$access_url_id]) &&
247
            is_array($_configuration[$access_url_id]) &&
248
            isset($_configuration[$access_url_id]['hosting_limit_users']) &&
249
            $_configuration[$access_url_id]['hosting_limit_users'] > 0) {
250
            $num = self::get_number_of_users();
251
            if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
252
                api_warn_hosting_contact('hosting_limit_users');
253
                Display::addFlash(Display::return_message(get_lang('PortalUsersLimitReached'), 'warning'));
254
255
                return false;
256
            }
257
        }
258
259 View Code Duplication
        if ($status === 1 &&
260
            isset($_configuration[$access_url_id]) &&
261
            is_array($_configuration[$access_url_id]) &&
262
            isset($_configuration[$access_url_id]['hosting_limit_teachers']) &&
263
            $_configuration[$access_url_id]['hosting_limit_teachers'] > 0
264
        ) {
265
            $num = self::get_number_of_users(1);
266
            if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
267
                Display::addFlash(Display::return_message(get_lang('PortalTeachersLimitReached'), 'warning'));
268
                api_warn_hosting_contact('hosting_limit_teachers');
269
270
                return false;
271
            }
272
        }
273
274 View Code Duplication
        if (empty($password)) {
275
            if ($authSource === PLATFORM_AUTH_SOURCE) {
276
                Display::addFlash(
277
                    Display::return_message(
278
                        get_lang('ThisFieldIsRequired').': '.get_lang(
279
                            'Password'
280
                        ),
281
                        'warning'
282
                    )
283
                );
284
285
                return false;
286
            }
287
288
            // We use the authSource as password.
289
            // The real validation will be by processed by the auth
290
            // source not Chamilo
291
            //$password = $authSource;
292
        }
293
294
        // database table definition
295
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
296
297
        // Checking the user language
298
        $languages = api_get_languages();
299
        $language = strtolower($language);
300
301 View Code Duplication
        if (isset($languages['folder'])) {
302
            if (!in_array($language, $languages['folder'])) {
303
                $language = api_get_setting('platformLanguage');
304
            }
305
        }
306
307
        if (!empty($currentUserId)) {
308
            $creator_id = $currentUserId;
309
        } else {
310
            $creator_id = 0;
311
        }
312
313
        $currentDate = api_get_utc_datetime();
314
        $now = new DateTime();
315
316
        if (empty($expirationDate) || $expirationDate == '0000-00-00 00:00:00') {
317
            // Default expiration date
318
            // if there is a default duration of a valid account then
319
            // we have to change the expiration_date accordingly
320
            // Accept 0000-00-00 00:00:00 as a null value to avoid issues with
321
            // third party code using this method with the previous (pre-1.10)
322
            // value of 0000...
323
            if (api_get_setting('account_valid_duration') != '') {
324
                $expirationDate = new DateTime($currentDate);
325
                $days = intval(api_get_setting('account_valid_duration'));
326
                $expirationDate->modify('+'.$days.' day');
327
            }
328
        } else {
329
            $expirationDate = api_get_utc_datetime($expirationDate);
330
            $expirationDate = new \DateTime($expirationDate, new DateTimeZone('UTC'));
331
        }
332
333
        $em = Database::getManager();
334
        $userManager = self::getManager();
335
336
        /** @var User $user */
337
        $user = $userManager->createUser();
338
339
        $user
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class FOS\UserBundle\Model\User as the method setOfficialCode() does only exist in the following sub-classes of FOS\UserBundle\Model\User: Chamilo\PageBundle\Entity\User, Chamilo\UserBundle\Entity\User. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
340
            ->setLastname($lastName)
341
            ->setFirstname($firstName)
342
            ->setUsername($loginName)
343
            ->setStatus($status)
344
            ->setPlainPassword($password)
345
            ->setEmail($email)
346
            ->setOfficialCode($official_code)
347
            ->setPictureUri($picture_uri)
348
            ->setCreatorId($creator_id)
349
            ->setAuthSource($authSource)
350
            ->setPhone($phone)
351
            ->setAddress($address)
352
            ->setLanguage($language)
353
            ->setRegistrationDate($now)
354
            ->setHrDeptId($hr_dept_id)
355
            ->setActive($active)
356
            ->setEnabled($active)
357
        ;
358
359
        if (!empty($expirationDate)) {
360
            $user->setExpirationDate($expirationDate);
0 ignored issues
show
Bug introduced by
It seems like $expirationDate defined by parameter $expirationDate on line 212 can also be of type string; however, Chamilo\UserBundle\Entit...er::setExpirationDate() does only seem to accept object<DateTime>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
361
        }
362
363
        $url = $em->getRepository('ChamiloCoreBundle:AccessUrl')->find(api_get_current_access_url_id());
364
365
        $accessRelUser = new AccessUrlRelUser();
366
        $accessRelUser->setUser($user);
367
        $accessRelUser->setPortal($url);
368
        $user->setPortal($accessRelUser);
369
370
        // Default group is student
371
        $group = 'student';
372
373
        switch ($status) {
374
            case STUDENT:
375
                $group = 'student';
376
                break;
377
            case COURSEMANAGER:
378
                $group = 'teacher';
379
                break;
380
            case DRH:
381
                $group = 'drh';
382
                break;
383
            case SESSIONADMIN:
384
                $group = 'session_manager';
385
                break;
386
            /*case QUESTION:
387
                $group = 'question_manager';
388
                break;*/
389
            case STUDENT_BOSS:
390
                $group = 'student_boss';
391
                break;
392
            case INVITEE:
393
                $group = 'invitee';
394
                break;
395
        }
396
397
        if ($isAdmin) {
398
            $group = 'admin';
399
        }
400
401
        $criteria = ['code' => $group];
402
        $group = $em->getRepository('ChamiloUserBundle:Group')->findOneBy($criteria);
403
        $user->setGroups(array($group));
404
405
        $userManager->updateUser($user, true);
406
        $userId = $user->getId();
407
408
        if (!empty($userId)) {
409
            $sql = "UPDATE $table_user SET user_id = $userId WHERE id = $userId";
410
            Database::query($sql);
411
412
            if ($isAdmin) {
413
                UserManager::add_user_as_admin($user);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
414
            }
415
416
            $extra['item_id'] = $userId;
417
418
            if (is_array($extra) && count($extra) > 0) {
419
                $courseFieldValue = new ExtraFieldValue('user');
420
                $courseFieldValue->saveFieldValues($extra);
421
            } else {
422
                // Create notify settings by default
423
                self::update_extra_field_value($userId, 'mail_notify_invitation', '1');
424
                self::update_extra_field_value($userId, 'mail_notify_message', '1');
425
                self::update_extra_field_value($userId, 'mail_notify_group_message', '1');
426
            }
427
428
            self::update_extra_field_value($userId, 'already_logged_in', 'false');
429
430
            if (!empty($email) && $send_mail) {
431
                $recipient_name = api_get_person_name(
432
                    $firstName,
433
                    $lastName,
434
                    null,
435
                    PERSON_NAME_EMAIL_ADDRESS
436
                );
437
                $tplSubject = new Template(
438
                    null,
439
                    false,
440
                    false,
441
                    false,
442
                    false,
443
                    false
444
                );
445
                $layoutSubject = $tplSubject->get_template(
446
                    'mail/subject_registration_platform.tpl'
447
                );
448
                $emailSubject = $tplSubject->fetch($layoutSubject);
449
                $sender_name = api_get_person_name(
450
                    api_get_setting('administratorName'),
451
                    api_get_setting('administratorSurname'),
452
                    null,
453
                    PERSON_NAME_EMAIL_ADDRESS
454
                );
455
                $email_admin = api_get_setting('emailAdministrator');
456
457
                $url = api_get_path(WEB_PATH);
458 View Code Duplication
                if (api_is_multiple_url_enabled()) {
459
                    $access_url_id = api_get_current_access_url_id();
460
                    if ($access_url_id != -1) {
461
                        $urlInfo = api_get_access_url($access_url_id);
462
                        if ($urlInfo) {
463
                            $url = $urlInfo['url'];
464
                        }
465
                    }
466
                }
467
468
                $tplContent = new Template(null, false, false, false, false, false);
469
                // variables for the default template
470
                $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
471
                $tplContent->assign('login_name', $loginName);
472
                $tplContent->assign('original_password', stripslashes($original_password));
473
                $tplContent->assign('mailWebPath', $url);
474
                $tplContent->assign('new_user', $user);
475
476
                $layoutContent = $tplContent->get_template('mail/content_registration_platform.tpl');
477
                $emailBody = $tplContent->fetch($layoutContent);
478
                /* MANAGE EVENT WITH MAIL */
479
                if (EventsMail::check_if_using_class('user_registration')) {
480
                    $values["about_user"] = $userId;
481
                    $values["password"] = $original_password;
482
                    $values["send_to"] = array($userId);
483
                    $values["prior_lang"] = null;
484
                    EventsDispatcher::events('user_registration', $values);
485
                } else {
486
                    $phoneNumber = isset($extra['mobile_phone_number']) ? $extra['mobile_phone_number'] : null;
487
488
                    $additionalParameters = array(
489
                        'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
490
                        'userId' => $userId,
491
                        'mobilePhoneNumber' => $phoneNumber,
492
                        'password' => $original_password
493
                    );
494
495
                    api_mail_html(
496
                        $recipient_name,
497
                        $email,
498
                        $emailSubject,
499
                        $emailBody,
500
                        $sender_name,
501
                        $email_admin,
502
                        null,
503
                        null,
504
                        null,
505
                        $additionalParameters
506
                    );
507
                }
508
509
                if ($sendEmailToAllAdmins) {
510
                    $adminList = self::get_all_administrators();
511
512
                    $tplContent = new Template(null, false, false, false, false, false);
513
                    // variables for the default template
514
                    $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
515
                    $tplContent->assign('user_added', $user);
516
517
                    $renderer = FormValidator::getDefaultRenderer();
518
519
                    // Form template
520
                    $elementTemplate = ' {label}: {element} <br />';
521
                    $renderer->setElementTemplate($elementTemplate);
522
                    /** @var FormValidator $form */
523
                    $form->freeze(null, $elementTemplate);
524
                    $form->removeElement('submit');
525
                    $formData = $form->returnForm();
526
                    $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId();
527
                    $tplContent->assign('link', Display::url($url, $url));
528
                    $tplContent->assign('form', $formData);
529
530
                    $layoutContent = $tplContent->get_template('mail/content_registration_platform_to_admin.tpl');
531
                    $emailBody = $tplContent->fetch($layoutContent);
532
                    $subject = get_lang('UserAdded');
533
534
                    foreach ($adminList as $adminId => $data) {
535
                        MessageManager::send_message_simple($adminId, $subject, $emailBody);
536
                    }
537
538
                }
539
                /* ENDS MANAGE EVENT WITH MAIL */
540
            }
541
542
            if (!empty($hook)) {
543
                $hook->setEventData(array(
544
                    'return' => $userId,
545
                    'originalPassword' => $original_password
546
                ));
547
                $hook->notifyCreateUser(HOOK_EVENT_TYPE_POST);
548
            }
549
            Event::addEvent(LOG_USER_CREATE, LOG_USER_ID, $userId);
550
        } else {
551
            Display::addFlash(Display::return_message(get_lang('ErrorContactPlatformAdmin')));
552
553
            return false;
554
        }
555
556
        return $userId;
557
    }
558
559
    /**
560
     * Can user be deleted? This function checks whether there's a course
561
     * in which the given user is the
562
     * only course administrator. If that is the case, the user can't be
563
     * deleted because the course would remain without a course admin.
564
     * @param int $user_id The user id
565
     * @return boolean true if user can be deleted
566
     * @assert (null) === false
567
     * @assert (-1) === false
568
     * @assert ('abc') === false
569
     */
570
    public static function can_delete_user($user_id)
571
    {
572
        $deny = api_get_configuration_value('deny_delete_users');
573
574
        if ($deny) {
575
            return false;
576
        }
577
578
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
579
        if ($user_id != strval(intval($user_id))) {
580
            return false;
581
        }
582
        if ($user_id === false) {
583
            return false;
584
        }
585
        $sql = "SELECT * FROM $table_course_user
586
                WHERE status = 1 AND user_id = ".$user_id;
587
        $res = Database::query($sql);
588
        while ($course = Database::fetch_object($res)) {
589
            $sql = "SELECT id FROM $table_course_user
590
                    WHERE status=1 AND c_id = ".intval($course->c_id);
591
            $res2 = Database::query($sql);
592
            if (Database::num_rows($res2) == 1) {
593
                return false;
594
            }
595
        }
596
597
        return true;
598
    }
599
600
    /**
601
     * Delete a user from the platform, and all its belongings. This is a
602
     * very dangerous function that should only be accessible by
603
     * super-admins. Other roles should only be able to disable a user,
604
     * which removes access to the platform but doesn't delete anything.
605
     * @param int The ID of th user to be deleted
606
     * @return boolean true if user is successfully deleted, false otherwise
607
     * @assert (null) === false
608
     * @assert ('abc') === false
609
     */
610
    public static function delete_user($user_id)
611
    {
612
        if ($user_id != strval(intval($user_id))) {
613
            return false;
614
        }
615
616
        if ($user_id === false) {
617
            return false;
618
        }
619
620
        if (!self::can_delete_user($user_id)) {
621
            return false;
622
        }
623
624
        $user = self::getManager()->find($user_id);
625
626
        if (empty($user)) {
627
            return false;
628
        }
629
630
        $usergroup_rel_user = Database :: get_main_table(TABLE_USERGROUP_REL_USER);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
631
        $table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
632
        $table_course = Database :: get_main_table(TABLE_MAIN_COURSE);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
633
        $table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
634
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
635
        $table_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
636
        $table_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
637
        $table_group = Database :: get_course_table(TABLE_GROUP_USER);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
638
        $table_work = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
639
640
        // Unsubscribe the user from all groups in all his courses
641
        $sql = "SELECT c.id 
642
                FROM $table_course c 
643
                INNER JOIN $table_course_user cu
644
                ON (c.id = cu.c_id)
645
                WHERE
646
                    cu.user_id = '".$user_id."' AND
647
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
648
                ";
649
650
        $res = Database::query($sql);
651
        while ($course = Database::fetch_object($res)) {
652
            $sql = "DELETE FROM $table_group
653
                    WHERE c_id = {$course->id} AND user_id = $user_id";
654
            Database::query($sql);
655
        }
656
657
        // Unsubscribe user from usergroup_rel_user
658
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
659
        Database::query($sql);
660
661
        // Unsubscribe user from all courses
662
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
663
        Database::query($sql);
664
665
        // Unsubscribe user from all courses in sessions
666
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
667
        Database::query($sql);
668
669
        // If the user was added as a id_coach then set the current admin as coach see BT#
670
        $currentUserId = api_get_user_id();
671
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
672
                WHERE id_coach = '".$user_id."'";
673
        Database::query($sql);
674
675
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
676
                WHERE session_admin_id = '".$user_id."'";
677
        Database::query($sql);
678
679
        // Unsubscribe user from all sessions
680
        $sql = "DELETE FROM $table_session_user
681
                WHERE user_id = '".$user_id."'";
682
        Database::query($sql);
683
684
        // Delete user picture
685
        /* TODO: Logic about api_get_setting('split_users_upload_directory') == 'true'
686
        a user has 4 different sized photos to be deleted. */
687
        $user_info = api_get_user_info($user_id);
688
689
        if (strlen($user_info['picture_uri']) > 0) {
690
            $path = self::getUserPathById($user_id, 'system');
691
            $img_path = $path.$user_info['picture_uri'];
692
            if (file_exists($img_path)) {
693
                unlink($img_path);
694
            }
695
        }
696
697
        // Delete the personal course categories
698
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
699
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
700
        Database::query($sql);
701
702
        // Delete user from the admin table
703
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
704
        Database::query($sql);
705
706
        // Delete the personal agenda-items from this user
707
        $agenda_table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
708
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
709
        Database::query($sql);
710
711
        $gradebook_results_table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
712
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
713
        Database::query($sql);
714
715
        $extraFieldValue = new ExtraFieldValue('user');
716
        $extraFieldValue->deleteValuesByItem($user_id);
717
718
        UrlManager::deleteUserFromAllUrls($user_id);
719
720
        if (api_get_setting('allow_social_tool') == 'true') {
721
            $userGroup = new UserGroup();
722
            //Delete user from portal groups
723
            $group_list = $userGroup->get_groups_by_user($user_id);
724
            if (!empty($group_list)) {
725
                foreach ($group_list as $group_id => $data) {
726
                    $userGroup->delete_user_rel_group($user_id, $group_id);
727
                }
728
            }
729
730
            // Delete user from friend lists
731
            SocialManager::remove_user_rel_user($user_id, true);
732
        }
733
734
        // Removing survey invitation
735
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
736
737
        // Delete students works
738
        $sql = "DELETE FROM $table_work WHERE user_id = $user_id AND c_id <> 0";
739
        Database::query($sql);
740
741
        $sql = "UPDATE c_item_property SET to_user_id = NULL
742
                WHERE to_user_id = '".$user_id."'";
743
        Database::query($sql);
744
745
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
746
                WHERE insert_user_id = '".$user_id."'";
747
        Database::query($sql);
748
749
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
750
                WHERE lastedit_user_id = '".$user_id."'";
751
        Database::query($sql);
752
753
        // Skills
754
        $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
755
        $sql = "DELETE FROM $table WHERE user_id = $user_id";
756
        Database::query($sql);
757
758
        $connection = Database::getManager()->getConnection();
759
        $tableExists = $connection->getSchemaManager()->tablesExist(['plugin_bbb_room']);
760
        if ($tableExists) {
761
             // Delete user from database
762
            $sql = "DELETE FROM plugin_bbb_room WHERE participant_id = $user_id";
763
            Database::query($sql);
764
        }
765
766
        // Delete user/ticket relationships :(
767
        $tableExists = $connection->getSchemaManager()->tablesExist(['ticket_ticket']);
768
        if ($tableExists) {
769
            TicketManager::deleteUserFromTicketSystem($user_id);
770
        }
771
772
        $tableExists = $connection->getSchemaManager()->tablesExist(['c_lp_category_user']);
773
        if ($tableExists) {
774
            $sql = "DELETE FROM c_lp_category_user WHERE user_id = $user_id";
775
            Database::query($sql);
776
        }
777
778
        // Delete user from database
779
        /*$sql = "DELETE FROM $table_user WHERE id = '".$user_id."'";
780
        Database::query($sql);*/
781
        self::getManager()->delete($user);
782
783
        // Add event to system log
784
        $user_id_manager = api_get_user_id();
785
786
        Event::addEvent(
787
            LOG_USER_DELETE,
788
            LOG_USER_ID,
789
            $user_id,
790
            api_get_utc_datetime(),
0 ignored issues
show
Bug introduced by
It seems like api_get_utc_datetime() can also be of type object<DateTime>; however, Event::addEvent() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
791
            $user_id_manager
792
        );
793
794
        Event::addEvent(
795
            LOG_USER_DELETE,
796
            LOG_USER_OBJECT,
797
            $user_info,
798
            api_get_utc_datetime(),
0 ignored issues
show
Bug introduced by
It seems like api_get_utc_datetime() can also be of type object<DateTime>; however, Event::addEvent() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
799
            $user_id_manager
800
        );
801
        $cacheAvailable = api_get_configuration_value('apc');
802 View Code Duplication
        if ($cacheAvailable === true) {
803
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
804
            if (apcu_exists($apcVar)) {
805
                apcu_delete($apcVar);
806
            }
807
        }
808
809
        return true;
810
    }
811
812
    /**
813
     * Deletes users completely. Can be called either as:
814
     * - UserManager::delete_users(1, 2, 3); or
815
     * - UserManager::delete_users(array(1, 2, 3));
816
     * @param array|int $ids
817
     * @return boolean  True if at least one user was successfuly deleted. False otherwise.
818
     * @author Laurent Opprecht
819
     * @uses UserManager::delete_user() to actually delete each user
820
     * @assert (null) === false
821
     * @assert (-1) === false
822
     * @assert (array(-1)) === false
823
     */
824
    public static function delete_users($ids = array())
825
    {
826
        $result = false;
827
        $ids = is_array($ids) ? $ids : func_get_args();
828
        if (!is_array($ids) || count($ids) == 0) {
829
            return false;
830
        }
831
        $ids = array_map('intval', $ids);
832
        foreach ($ids as $id) {
833
            if (empty($id) || $id < 1) {
834
                continue;
835
            }
836
            $deleted = self::delete_user($id);
837
            $result = $deleted || $result;
838
        }
839
840
        return $result;
841
    }
842
843
    /**
844
     * Disable users. Can be called either as:
845
     * - UserManager::deactivate_users(1, 2, 3);
846
     * - UserManager::deactivate_users(array(1, 2, 3));
847
     * @param array|int $ids
848
     * @return boolean
849
     * @author Laurent Opprecht
850
     * @assert (null) === false
851
     * @assert (array(-1)) === false
852
     */
853 View Code Duplication
    public static function deactivate_users($ids = array())
854
    {
855
        if (empty($ids)) {
856
            return false;
857
        }
858
859
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
860
861
        $ids = is_array($ids) ? $ids : func_get_args();
862
        $ids = array_map('intval', $ids);
863
        $ids = implode(',', $ids);
864
865
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
866
        $r = Database::query($sql);
867
        if ($r !== false) {
868
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
869
        }
870
        return $r;
871
    }
872
873
    /**
874
     * Enable users. Can be called either as:
875
     * - UserManager::activate_users(1, 2, 3);
876
     * - UserManager::activate_users(array(1, 2, 3));
877
     * @param array|int IDs of the users to enable
878
     * @return boolean
879
     * @author Laurent Opprecht
880
     * @assert (null) === false
881
     * @assert (array(-1)) === false
882
     */
883 View Code Duplication
    public static function activate_users($ids = array())
884
    {
885
        if (empty($ids)) {
886
            return false;
887
        }
888
889
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
890
891
        $ids = is_array($ids) ? $ids : func_get_args();
892
        $ids = array_map('intval', $ids);
893
        $ids = implode(',', $ids);
894
895
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
896
        $r = Database::query($sql);
897
        if ($r !== false) {
898
            Event::addEvent(LOG_USER_ENABLE, LOG_USER_ID, $ids);
899
        }
900
        return $r;
901
    }
902
903
    /**
904
     * Update user information with new openid
905
     * @param int $user_id
906
     * @param string $openid
907
     * @return boolean true if the user information was updated
908
     * @assert (false,'') === false
909
     * @assert (-1,'') === false
910
     */
911
    public static function update_openid($user_id, $openid)
912
    {
913
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
914
        if ($user_id != strval(intval($user_id))) {
915
            return false;
916
        }
917
        if ($user_id === false) {
918
            return false;
919
        }
920
        $sql = "UPDATE $table_user SET
921
                openid='".Database::escape_string($openid)."'";
922
        $sql .= " WHERE id= $user_id";
923
924
        return Database::query($sql);
925
    }
926
927
    /**
928
     * Update user information with all the parameters passed to this function
929
     * @param int The ID of the user to be updated
930
     * @param string The user's firstname
931
     * @param string The user's lastname
932
     * @param string The user's username (login)
933
     * @param string The user's password
934
     * @param string The authentication source (default: "platform")
935
     * @param string The user's e-mail address
936
     * @param int The user's status
937
     * @param string The user's official code (usually just an internal institutional code)
938
     * @param string The user's phone number
939
     * @param string The user's picture URL (internal to the Chamilo directory)
940
     * @param int The user ID of the person who registered this user (optional, defaults to null)
941
     * @param int The department of HR in which the user is registered (optional, defaults to 0)
942
     * @param array A series of additional fields to add to this user as extra fields (optional, defaults to null)
943
     * @return boolean|integer False on error, or the user ID if the user information was updated
944
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
945
     */
946
    public static function update_user(
947
        $user_id,
948
        $firstname,
949
        $lastname,
950
        $username,
951
        $password = null,
952
        $auth_source = null,
953
        $email,
954
        $status,
955
        $official_code,
956
        $phone,
957
        $picture_uri,
958
        $expiration_date,
959
        $active,
960
        $creator_id = null,
961
        $hr_dept_id = 0,
962
        $extra = null,
963
        $language = 'english',
964
        $encrypt_method = '',
965
        $send_email = false,
966
        $reset_password = 0,
967
        $address = null
968
    ) {
969
        $hook = HookUpdateUser::create();
970
        if (!empty($hook)) {
971
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_PRE);
972
        }
973
        $original_password = $password;
974
975
        if ($user_id != strval(intval($user_id))) {
976
            return false;
977
        }
978
979
        if (empty($user_id)) {
980
            return false;
981
        }
982
983
        $userManager = self::getManager();
984
        /** @var Chamilo\UserBundle\Entity\User $user */
985
        $user = self::getRepository()->find($user_id);
986
987
        if (empty($user)) {
988
            return false;
989
        }
990
991
        if ($reset_password == 0) {
992
            $password = null;
993
            $auth_source = $user->getAuthSource();
994
        } elseif ($reset_password == 1) {
995
            $original_password = $password = api_generate_password();
996
            $auth_source = PLATFORM_AUTH_SOURCE;
997
        } elseif ($reset_password == 2) {
998
            $password = $password;
0 ignored issues
show
Bug introduced by
Why assign $password to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
999
            $auth_source = PLATFORM_AUTH_SOURCE;
1000
        } elseif ($reset_password == 3) {
1001
            $password = $password;
0 ignored issues
show
Bug introduced by
Why assign $password to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
1002
            $auth_source = $auth_source;
0 ignored issues
show
Bug introduced by
Why assign $auth_source to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
1003
        }
1004
1005
        // Checking the user language
1006
        $languages = api_get_platform_isocodes();
1007
        if (!in_array($language, $languages)) {
1008
            $language = api_get_setting('platformLanguage');
1009
        }
1010
1011
        $change_active = 0;
1012
        $isUserActive = $user->getActive();
1013
        if ($isUserActive != $active) {
1014
            $change_active = 1;
1015
        }
1016
1017
        $originalUsername = $user->getUsername();
1018
1019
        // If username is different from original then check if it exists.
1020
        if ($originalUsername !== $username) {
1021
            $available = self::is_username_available($username);
1022
            if ($available === false) {
1023
                return false;
1024
            }
1025
        }
1026
1027
        if (!empty($expiration_date)) {
1028
            $expiration_date = api_get_utc_datetime($expiration_date);
1029
            $expiration_date = new \DateTime(
1030
                $expiration_date,
1031
                new DateTimeZone('UTC')
1032
            );
1033
        }
1034
1035
        $user
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class FOS\UserBundle\Model\User as the method setHrDeptId() does only exist in the following sub-classes of FOS\UserBundle\Model\User: Chamilo\PageBundle\Entity\User, Chamilo\UserBundle\Entity\User. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
1036
            ->setLastname($lastname)
1037
            ->setFirstname($firstname)
1038
            ->setUsername($username)
1039
            ->setStatus($status)
1040
            ->setAuthSource($auth_source)
1041
            ->setLanguage($language)
1042
            ->setEmail($email)
1043
            ->setOfficialCode($official_code)
1044
            ->setPhone($phone)
1045
            ->setAddress($address)
1046
            ->setPictureUri($picture_uri)
1047
            ->setExpirationDate($expiration_date)
1048
            ->setActive($active)
1049
            ->setEnabled($active)
1050
            ->setHrDeptId($hr_dept_id)
1051
        ;
1052
1053
        if (!is_null($password)) {
1054
            $user->setPlainPassword($password);
1055
        }
1056
1057
        $userManager->updateUser($user, true);
1058
1059
        if ($change_active == 1) {
1060
            if ($active == 1) {
1061
                $event_title = LOG_USER_ENABLE;
1062
            } else {
1063
                $event_title = LOG_USER_DISABLE;
1064
            }
1065
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
1066
        }
1067
1068
        if (is_array($extra) && count($extra) > 0) {
1069
            $res = true;
1070
            foreach ($extra as $fname => $fvalue) {
1071
                $res = $res && self::update_extra_field_value(
1072
                    $user_id,
1073
                    $fname,
1074
                    $fvalue
1075
                );
1076
            }
1077
        }
1078
1079
        if (!empty($email) && $send_email) {
1080
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
1081
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('YourReg').' '.api_get_setting('siteName');
1082
            $sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);
1083
            $email_admin = api_get_setting('emailAdministrator');
1084
1085
            if (api_is_multiple_url_enabled()) {
1086
                $access_url_id = api_get_current_access_url_id();
1087
                if ($access_url_id != -1) {
1088
                    $url = api_get_access_url($access_url_id);
1089
                    $emailbody = get_lang('Dear')." ".stripslashes(api_get_person_name($firstname, $lastname)).",\n\n".
1090
                        get_lang('YouAreReg')." ".api_get_setting('siteName')." ".get_lang('WithTheFollowingSettings')."\n\n".
1091
                        get_lang('Username')." : ".$username.(($reset_password > 0) ? "\n".
1092
                        get_lang('Pass')." : ".stripslashes($original_password) : "")."\n\n".
1093
                        get_lang('Address')." ".api_get_setting('siteName')." ".get_lang('Is')." : ".$url['url']."\n\n".
1094
                        get_lang('Problem')."\n\n".
1095
                        get_lang('SignatureFormula').",\n\n".
1096
                        api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".
1097
                        get_lang('Manager')." ".api_get_setting('siteName')."\nT. ".api_get_setting('administratorTelephone')."\n".
1098
                        get_lang('Email')." : ".api_get_setting('emailAdministrator');
1099
                }
1100
            } else {
1101
                $emailbody = get_lang('Dear')." ".stripslashes(api_get_person_name($firstname, $lastname)).",\n\n".
1102
                    get_lang('YouAreReg')." ".api_get_setting('siteName')." ".get_lang('WithTheFollowingSettings')."\n\n".
1103
                    get_lang('Username')." : ".$username.(($reset_password > 0) ? "\n".
1104
                    get_lang('Pass')." : ".stripslashes($original_password) : "")."\n\n".
1105
                    get_lang('Address')." ".api_get_setting('siteName')." ".get_lang('Is')." : ".api_get_path(WEB_PATH)."\n\n".
1106
                    get_lang('Problem')."\n\n".
1107
                    get_lang('SignatureFormula').",\n\n".
1108
                    api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".
1109
                    get_lang('Manager')." ".api_get_setting('siteName')."\nT. ".api_get_setting('administratorTelephone')."\n".
1110
                    get_lang('Email')." : ".api_get_setting('emailAdministrator');
1111
            }
1112
1113
            $emailbody = nl2br($emailbody);
1114
            api_mail_html(
1115
                $recipient_name,
1116
                $email,
1117
                $emailsubject,
1118
                $emailbody,
1119
                $sender_name,
1120
                $email_admin
1121
            );
1122
        }
1123
1124
        if (!empty($hook)) {
1125
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_POST);
1126
        }
1127
1128
        $cacheAvailable = api_get_configuration_value('apc');
1129 View Code Duplication
        if ($cacheAvailable === true) {
1130
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1131
            if (apcu_exists($apcVar)) {
1132
                apcu_delete($apcVar);
1133
            }
1134
        }
1135
1136
        return $user->getId();
1137
    }
1138
1139
    /**
1140
     * Disables or enables a user
1141
     * @param int $user_id
1142
     * @param int $active Enable or disable
1143
     * @return void
1144
     * @assert (-1,0) === false
1145
     * @assert (1,1) === true
1146
     */
1147
    private static function change_active_state($user_id, $active)
1148
    {
1149
        if (strval(intval($user_id)) != $user_id) {
1150
            return false;
1151
        }
1152
        if ($user_id < 1) {
1153
            return false;
1154
        }
1155
        $user_id = intval($user_id);
1156
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1157
        $sql = "UPDATE $table_user SET active = '$active' WHERE id = $user_id";
1158
        $r = Database::query($sql);
1159
        $ev = LOG_USER_DISABLE;
1160
        if ($active == 1) {
1161
            $ev = LOG_USER_ENABLE;
1162
        }
1163
        if ($r !== false) {
1164
            Event::addEvent($ev, LOG_USER_ID, $user_id);
1165
        }
1166
1167
        return $r;
1168
    }
1169
1170
    /**
1171
     * Disables a user
1172
     * @param int User id
1173
     * @return bool
1174
     * @uses UserManager::change_active_state() to actually disable the user
1175
     * @assert (0) === false
1176
     */
1177
    public static function disable($user_id)
1178
    {
1179
        if (empty($user_id)) {
1180
            return false;
1181
        }
1182
        self::change_active_state($user_id, 0);
1183
        return true;
1184
    }
1185
1186
    /**
1187
     * Enable a user
1188
     * @param int User id
1189
     * @return bool
1190
     * @uses UserManager::change_active_state() to actually disable the user
1191
     * @assert (0) === false
1192
     */
1193
    public static function enable($user_id)
1194
    {
1195
        if (empty($user_id)) {
1196
            return false;
1197
        }
1198
        self::change_active_state($user_id, 1);
1199
        return true;
1200
    }
1201
1202
    /**
1203
     * Returns the user's id based on the original id and field name in
1204
     * the extra fields. Returns 0 if no user was found. This function is
1205
     * mostly useful in the context of a web services-based sinchronization
1206
     * @param string Original user id
1207
     * @param string Original field name
1208
     * @return int User id
1209
     * @assert ('0','---') === 0
1210
     */
1211 View Code Duplication
    public static function get_user_id_from_original_id($original_user_id_value, $original_user_id_name)
1212
    {
1213
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1214
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1215
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1216
        $sql = "SELECT item_id as user_id
1217
                FROM $t_uf uf
1218
                INNER JOIN $t_ufv ufv
1219
                ON ufv.field_id=uf.id
1220
                WHERE
1221
                    variable='$original_user_id_name' AND
1222
                    value='$original_user_id_value' AND
1223
                    extra_field_type = $extraFieldType
1224
                ";
1225
        $res = Database::query($sql);
1226
        $row = Database::fetch_object($res);
1227
        if ($row) {
1228
            return $row->user_id;
1229
        } else {
1230
            return 0;
1231
        }
1232
    }
1233
1234
    /**
1235
     * Check if a username is available
1236
     * @param string $username the wanted username
1237
     * @return boolean true if the wanted username is available
1238
     * @assert ('') === false
1239
     * @assert ('xyzxyzxyz') === true
1240
     */
1241 View Code Duplication
    public static function is_username_available($username)
1242
    {
1243
        if (empty($username)) {
1244
            return false;
1245
        }
1246
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1247
        $sql = "SELECT username FROM $table_user
1248
                WHERE username = '".Database::escape_string($username)."'";
1249
        $res = Database::query($sql);
1250
1251
        return Database::num_rows($res) == 0;
1252
    }
1253
1254
    /**
1255
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1256
     * @param string $firstname The first name of the user.
1257
     * @param string $lastname The last name of the user.
1258
     * @return string Suggests a username that contains only ASCII-letters and digits,
1259
     * without check for uniqueness within the system.
1260
     * @author Julio Montoya Armas
1261
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1262
     * @assert ('','') === false
1263
     * @assert ('a','b') === 'ab'
1264
     */
1265
    public static function create_username($firstname, $lastname)
1266
    {
1267
        if (empty($firstname) && empty($lastname)) {
1268
            return false;
1269
        }
1270
1271
        $firstname = api_substr(preg_replace(USERNAME_PURIFIER, '', $firstname), 0, 1); // The first letter only.
1272
        //Looking for a space in the lastname
1273
        $pos = api_strpos($lastname, ' ');
1274
        if ($pos !== false) {
1275
            $lastname = api_substr($lastname, 0, $pos);
1276
        }
1277
1278
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1279
        $username = $firstname.$lastname;
1280
        if (empty($username)) {
1281
            $username = 'user';
1282
        }
1283
1284
        $username = URLify::transliterate($username);
1285
1286
        return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3));
1287
    }
1288
1289
    /**
1290
     * Creates a unique username, using:
1291
     * 1. the first name and the last name of a user;
1292
     * 2. an already created username but not checked for uniqueness yet.
1293
     * @param string $firstname                The first name of a given user. If the second parameter $lastname is NULL, then this
1294
     * parameter is treated as username which is to be checked for uniqueness and to be modified when it is necessary.
1295
     * @param string $lastname                The last name of the user.
1296
     * @return string                        Returns a username that contains only ASCII-letters and digits, and that is unique within the system.
1297
     * Note: When the method is called several times with same parameters, its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1298
     * @author Ivan Tcholakov, 2009
1299
     */
1300
    public static function create_unique_username($firstname, $lastname = null)
1301
    {
1302
        if (is_null($lastname)) {
1303
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1304
            // For making this method tolerant of mistakes, let us transliterate and purify the suggested input username anyway.
1305
            // So, instead of the sentence $username = $firstname; we place the following:
1306
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1307
        } else {
1308
            $username = self::create_username($firstname, $lastname);
1309
        }
1310
        if (!self::is_username_available($username)) {
0 ignored issues
show
Security Bug introduced by
It seems like $username defined by self::create_username($firstname, $lastname) on line 1308 can also be of type false; however, UserManager::is_username_available() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1311
            $i = 2;
1312
            $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1313
            while (!self::is_username_available($temp_username)) {
1314
                $i++;
1315
                $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1316
            }
1317
            $username = $temp_username;
1318
        }
1319
1320
        $username = URLify::transliterate($username);
1321
1322
        return $username;
1323
    }
1324
1325
    /**
1326
     * Modifies a given username accordingly to the specification for valid characters and length.
1327
     * @param $username string          The input username.
1328
     * @param bool $strict (optional)   When this flag is TRUE, the result is guaranteed for full compliance,
1329
     * otherwise compliance may be partial. The default value is FALSE.
1330
     * @return string                   The resulting purified username.
1331
     */
1332
    public static function purify_username($username, $strict = false)
1333
    {
1334
        if ($strict) {
1335
            // 1. Conversion of unacceptable letters (latinian letters with accents for example)
1336
            // into ASCII letters in order they not to be totally removed.
1337
            // 2. Applying the strict purifier.
1338
            // 3. Length limitation.
1339
            $return = api_get_setting('login_is_email') === 'true' ? substr(preg_replace(USERNAME_PURIFIER_MAIL, '', $username), 0, USERNAME_MAX_LENGTH) : substr(preg_replace(USERNAME_PURIFIER, '', $username), 0, USERNAME_MAX_LENGTH);
1340
            $return = URLify::transliterate($return);
1341
1342
            return $return;
1343
        }
1344
1345
        // 1. Applying the shallow purifier.
1346
        // 2. Length limitation.
1347
        return substr(preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username), 0, USERNAME_MAX_LENGTH);
1348
    }
1349
1350
    /**
1351
     * Checks whether the user id exists in the database
1352
     *
1353
     * @param int User id
1354
     * @return bool True if user id was found, false otherwise
1355
     */
1356 View Code Duplication
    public static function is_user_id_valid($userId)
1357
    {
1358
        $resultData = Database::select(
1359
            'COUNT(1) AS count',
1360
            Database::get_main_table(TABLE_MAIN_USER),
1361
            [
1362
                'where' => ['id = ?' => intval($userId)]
1363
            ],
1364
            'first'
1365
        );
1366
1367
        if ($resultData === false) {
1368
            return false;
1369
        }
1370
1371
        return $resultData['count'] > 0;
1372
    }
1373
1374
    /**
1375
     * Checks whether a given username matches to the specification strictly. The empty username is assumed here as invalid.
1376
     * Mostly this function is to be used in the user interface built-in validation routines for providing feedback while usernames are enterd manually.
1377
     * @param string $username The input username.
1378
     * @return bool Returns TRUE if the username is valid, FALSE otherwise.
1379
     */
1380
    public static function is_username_valid($username)
1381
    {
1382
        return !empty($username) && $username == self::purify_username($username, true);
1383
    }
1384
1385
    /**
1386
     * Checks whether a username is empty. If the username contains whitespace characters, such as spaces, tabulators, newlines, etc.,
1387
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1388
     * @param string $username The given username.
1389
     * @return bool  Returns TRUE if length of the username exceeds the limit, FALSE otherwise.
1390
     */
1391
    public static function is_username_empty($username)
1392
    {
1393
        return (strlen(self::purify_username($username, false)) == 0);
1394
    }
1395
1396
    /**
1397
     * Checks whether a username is too long or not.
1398
     * @param string $username The given username, it should contain only ASCII-letters and digits.
1399
     * @return bool Returns TRUE if length of the username exceeds the limit, FALSE otherwise.
1400
     */
1401
    public static function is_username_too_long($username)
1402
    {
1403
        return (strlen($username) > USERNAME_MAX_LENGTH);
1404
    }
1405
1406
    /**
1407
    * Get the users by ID
1408
    * @param array $ids student ids
1409
    * @param string $active
1410
    * @param string $order
1411
    * @param string $limit
1412
    * @return array $result student information
1413
    */
1414
    public static function get_user_list_by_ids($ids = array(), $active = null, $order = null, $limit = null)
1415
    {
1416
        if (empty($ids)) {
1417
1418
            return array();
1419
        }
1420
1421
        $ids = is_array($ids) ? $ids : array($ids);
1422
        $ids = array_map('intval', $ids);
1423
        $ids = implode(',', $ids);
1424
1425
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1426
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1427
        if (!is_null($active)) {
1428
            $sql .= ' AND active='.($active ? '1' : '0');
1429
        }
1430
1431
        if (!is_null($order)) {
1432
            $order = Database::escape_string($order);
1433
            $sql .= ' ORDER BY '.$order;
1434
        }
1435
1436
        if (!is_null($limit)) {
1437
            $limit = Database::escape_string($limit);
1438
            $sql .= ' LIMIT '.$limit;
1439
        }
1440
1441
        $rs = Database::query($sql);
1442
        $result = array();
1443
        while ($row = Database::fetch_array($rs)) {
1444
            $result[] = $row;
1445
        }
1446
1447
        return $result;
1448
    }
1449
1450
    /**
1451
     * Get a list of users of which the given conditions match with an = 'cond'
1452
     * @param array $conditions a list of condition (example : status=>STUDENT)
1453
     * @param array $order_by a list of fields on which sort
1454
     * @return array An array with all users of the platform.
1455
     * @todo optional course code parameter, optional sorting parameters...
1456
     * @todo security filter order by
1457
     */
1458
    public static function get_user_list(
1459
        $conditions = [],
1460
        $order_by = [],
1461
        $limit_from = false,
1462
        $limit_to = false
1463
    ) {
1464
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1465
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1466
        $urlId = api_get_current_access_url_id();
1467
1468
        $return_array = array();
1469
        $sql = "SELECT user.* FROM $user_table user
1470
                INNER JOIN $userUrlTable url_user
1471
                ON (user.user_id = url_user.user_id)
1472
                WHERE url_user.access_url_id = $urlId
1473
        ";
1474
1475
        if (count($conditions) > 0) {
1476
            foreach ($conditions as $field => $value) {
1477
                $field = Database::escape_string($field);
1478
                $value = Database::escape_string($value);
1479
                $sql .= " AND $field = '$value'";
1480
            }
1481
        }
1482
1483 View Code Duplication
        if (count($order_by) > 0) {
1484
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1485
        }
1486
1487
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1488
            $limit_from = intval($limit_from);
1489
            $limit_to = intval($limit_to);
1490
            $sql .= " LIMIT $limit_from, $limit_to";
1491
        }
1492
        $sql_result = Database::query($sql);
1493 View Code Duplication
        while ($result = Database::fetch_array($sql_result)) {
1494
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1495
            $return_array[] = $result;
1496
        }
1497
        return $return_array;
1498
    }
1499
1500
    /**
1501
     * Get a list of users of which the given conditions match with a LIKE '%cond%'
1502
     * @param array $conditions a list of condition (exemple : status=>STUDENT)
1503
     * @param array $order_by a list of fields on which sort
1504
     * @return array An array with all users of the platform.
1505
     * @todo optional course code parameter, optional sorting parameters...
1506
     * @todo security filter order_by
1507
     */
1508
    public static function get_user_list_like(
1509
        $conditions = array(),
1510
        $order_by = array(),
1511
        $simple_like = false,
1512
        $condition = 'AND'
1513
    ) {
1514
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1515
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1516
        $return_array = array();
1517
        $sql_query = "SELECT user.id FROM $user_table user ";
1518
1519
        if (api_is_multiple_url_enabled()) {
1520
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
1521
        }
1522
1523
        if (count($conditions) > 0) {
1524
            $sql_query .= ' WHERE ';
1525
            $temp_conditions = array();
1526
            foreach ($conditions as $field => $value) {
1527
                $field = Database::escape_string($field);
1528
                $value = Database::escape_string($value);
1529 View Code Duplication
                if ($simple_like) {
1530
                    $temp_conditions[] = $field." LIKE '$value%'";
1531
                } else {
1532
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1533
                }
1534
            }
1535
            if (!empty($temp_conditions)) {
1536
                $sql_query .= implode(' '.$condition.' ', $temp_conditions);
1537
            }
1538
1539
            if (api_is_multiple_url_enabled()) {
1540
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1541
            }
1542
        } else {
1543
            if (api_is_multiple_url_enabled()) {
1544
                $sql_query .= ' WHERE auru.access_url_id = '.api_get_current_access_url_id();
1545
            }
1546
        }
1547 View Code Duplication
        if (count($order_by) > 0) {
1548
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1549
        }
1550
1551
        $sql_result = Database::query($sql_query);
1552
        while ($result = Database::fetch_array($sql_result)) {
1553
            $userInfo = api_get_user_info($result['id']);
1554
            $return_array[] = $userInfo;
1555
        }
1556
1557
        return $return_array;
1558
    }
1559
1560
    /**
1561
     * Get user picture URL or path from user ID (returns an array).
1562
     * The return format is a complete path, enabling recovery of the directory
1563
     * with dirname() or the file with basename(). This also works for the
1564
     * functions dealing with the user's productions, as they are located in
1565
     * the same directory.
1566
     * @param   integer   $id User ID
1567
     * @param   string    $type Type of path to return (can be 'system', 'web')
1568
     * @param   array $userInfo user information to avoid query the DB
1569
     * returns the /main/img/unknown.jpg image set it at true
1570
     *
1571
     * @return    array     Array of 2 elements: 'dir' and 'file' which contain
1572
     * the dir and file as the name implies if image does not exist it will
1573
     * return the unknow image if anonymous parameter is true if not it returns an empty array
1574
     */
1575 View Code Duplication
    public static function get_user_picture_path_by_id($id, $type = 'web', $userInfo = [])
1576
    {
1577
        switch ($type) {
1578
            case 'system': // Base: absolute system path.
1579
                $base = api_get_path(SYS_CODE_PATH);
1580
                break;
1581
            case 'web': // Base: absolute web path.
1582
            default:
1583
                $base = api_get_path(WEB_CODE_PATH);
1584
                break;
1585
        }
1586
1587
        $anonymousPath = array(
1588
            'dir' => $base.'img/',
1589
            'file' => 'unknown.jpg',
1590
            'email' => ''
1591
        );
1592
1593
        if (empty($id) || empty($type)) {
1594
            return $anonymousPath;
1595
        }
1596
1597
        $id = intval($id);
1598
        if (empty($userInfo)) {
1599
            $user_table = Database::get_main_table(TABLE_MAIN_USER);
1600
            $sql = "SELECT email, picture_uri FROM $user_table
1601
                    WHERE id=".$id;
1602
            $res = Database::query($sql);
1603
1604
            if (!Database::num_rows($res)) {
1605
                return $anonymousPath;
1606
            }
1607
            $user = Database::fetch_array($res);
1608
            if (empty($user['picture_uri'])) {
1609
                return $anonymousPath;
1610
            }
1611
        } else {
1612
            $user = $userInfo;
1613
        }
1614
1615
        $pictureFilename = trim($user['picture_uri']);
1616
1617
        $dir = self::getUserPathById($id, $type);
1618
1619
        return array(
1620
            'dir' => $dir,
1621
            'file' => $pictureFilename,
1622
            'email' => $user['email']
1623
        );
1624
    }
1625
1626
    /**
1627
     * *** READ BEFORE REVIEW THIS FUNCTION ***
1628
     * This function is a exact copy from get_user_picture_path_by_id() and it was create it to avoid
1629
     * a recursive calls for get_user_picture_path_by_id() in another functions when you update a user picture
1630
     * in same script, so you can find this function usage in update_user_picture() function.
1631
     *
1632
     * @param   integer   $id User ID
1633
     * @param   string    $type Type of path to return (can be 'system', 'web')
1634
     * @param   array $userInfo user information to avoid query the DB
1635
     * returns the /main/img/unknown.jpg image set it at true
1636
     *
1637
     * @return    array     Array of 2 elements: 'dir' and 'file' which contain
1638
     * the dir and file as the name implies if image does not exist it will
1639
     * return the unknown image if anonymous parameter is true if not it returns an empty array
1640
     */
1641 View Code Duplication
    public static function getUserPicturePathById($id, $type = 'web', $userInfo = [])
1642
    {
1643
        switch ($type) {
1644
            case 'system': // Base: absolute system path.
1645
                $base = api_get_path(SYS_CODE_PATH);
1646
                break;
1647
            case 'web': // Base: absolute web path.
1648
            default:
1649
                $base = api_get_path(WEB_CODE_PATH);
1650
                break;
1651
        }
1652
1653
        $anonymousPath = array(
1654
            'dir' => $base.'img/',
1655
            'file' => 'unknown.jpg',
1656
            'email' => ''
1657
        );
1658
1659
        if (empty($id) || empty($type)) {
1660
            return $anonymousPath;
1661
        }
1662
1663
        $id = intval($id);
1664
1665
        if (empty($userInfo)) {
1666
            $user_table = Database::get_main_table(TABLE_MAIN_USER);
1667
            $sql = "SELECT email, picture_uri FROM $user_table WHERE id=$id";
1668
            $res = Database::query($sql);
1669
1670
            if (!Database::num_rows($res)) {
1671
                return $anonymousPath;
1672
            }
1673
            $user = Database::fetch_array($res);
1674
1675
            if (empty($user['picture_uri'])) {
1676
                return $anonymousPath;
1677
            }
1678
        } else {
1679
            $user = $userInfo;
1680
        }
1681
1682
        $pictureFilename = trim($user['picture_uri']);
1683
1684
        $dir = self::getUserPathById($id, $type);
1685
1686
        return array(
1687
            'dir' => $dir,
1688
            'file' => $pictureFilename,
1689
            'email' => $user['email']
1690
        );
1691
    }
1692
1693
    /**
1694
     * Get user path from user ID (returns an array).
1695
     * The return format is a complete path to a folder ending with "/"
1696
     * In case the first level of subdirectory of users/ does not exist, the
1697
     * function will attempt to create it. Probably not the right place to do it
1698
     * but at least it avoids headaches in many other places.
1699
     * @param   integer $id User ID
1700
     * @param   string  $type Type of path to return (can be 'system', 'web', 'last')
1701
     * @return  string  User folder path (i.e. /var/www/chamilo/app/upload/users/1/1/)
1702
     */
1703
    public static function getUserPathById($id, $type)
1704
    {
1705
        $id = intval($id);
1706
        if (!$id) {
1707
            return null;
1708
        }
1709
1710
        $userPath = "users/$id/";
1711
        if (api_get_setting('split_users_upload_directory') === 'true') {
1712
            $userPath = 'users/'.substr((string) $id, 0, 1).'/'.$id.'/';
1713
            // In exceptional cases, on some portals, the intermediate base user
1714
            // directory might not have been created. Make sure it is before
1715
            // going further.
1716
1717
            $rootPath = api_get_path(SYS_UPLOAD_PATH).'users/'.substr((string) $id, 0, 1);
1718
            if (!is_dir($rootPath)) {
1719
                $perm = api_get_permissions_for_new_directories();
1720
                try {
1721
                    mkdir($rootPath, $perm);
1722
                } catch (Exception $e) {
1723
                    error_log($e->getMessage());
1724
                }
1725
            }
1726
        }
1727
        switch ($type) {
1728
            case 'system': // Base: absolute system path.
1729
                $userPath = api_get_path(SYS_UPLOAD_PATH).$userPath;
1730
                break;
1731
            case 'web': // Base: absolute web path.
1732
                $userPath = api_get_path(WEB_UPLOAD_PATH).$userPath;
1733
                break;
1734
            case 'last': // Only the last part starting with users/
1735
                break;
1736
        }
1737
1738
        return $userPath;
1739
    }
1740
1741
    /**
1742
     * Gets the current user image
1743
     * @param string $user_id
1744
     * @param int $size it can be USER_IMAGE_SIZE_SMALL,
1745
     * USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1746
     * @param bool $addRandomId
1747
     * @param array $userInfo to avoid query the DB
1748
     *
1749
     * @return string
1750
     */
1751
    public static function getUserPicture(
1752
        $user_id,
1753
        $size = USER_IMAGE_SIZE_MEDIUM,
1754
        $addRandomId = true,
1755
        $userInfo = []
1756
    ) {
1757
        // Make sure userInfo is defined. Otherwise, define it!
1758
        if (empty($userInfo) || !is_array($userInfo) || count($userInfo) == 0) {
1759
            if (empty($user_id)) {
1760
                return '';
1761
            } else {
1762
                $userInfo = api_get_user_info($user_id);
1763
            }
1764
        }
1765
1766
        $imageWebPath = self::get_user_picture_path_by_id($user_id, 'web', $userInfo);
0 ignored issues
show
Security Bug introduced by
It seems like $userInfo defined by api_get_user_info($user_id) on line 1762 can also be of type false; however, UserManager::get_user_picture_path_by_id() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1767
        $pictureWebFile = $imageWebPath['file'];
1768
        $pictureWebDir = $imageWebPath['dir'];
1769
1770
        $pictureAnonymousSize = '128';
1771
        $gravatarSize = 22;
1772
        $realSizeName = 'small_';
1773
1774
        switch ($size) {
1775
            case USER_IMAGE_SIZE_SMALL:
1776
                $pictureAnonymousSize = '32';
1777
                $realSizeName = 'small_';
1778
                $gravatarSize = 22;
1779
                break;
1780
            case USER_IMAGE_SIZE_MEDIUM:
1781
                $pictureAnonymousSize = '64';
1782
                $realSizeName = 'medium_';
1783
                $gravatarSize = 50;
1784
                break;
1785
            case USER_IMAGE_SIZE_ORIGINAL:
1786
                $pictureAnonymousSize = '128';
1787
                $realSizeName = '';
1788
                $gravatarSize = 200;
1789
                break;
1790
            case USER_IMAGE_SIZE_BIG:
1791
                $pictureAnonymousSize = '128';
1792
                $realSizeName = 'big_';
1793
                $gravatarSize = 200;
1794
                break;
1795
        }
1796
1797
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1798
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1799
        if ($pictureWebFile == 'unknown.jpg' || empty($pictureWebFile)) {
1800
            if ($gravatarEnabled === 'true') {
1801
                $file = self::getGravatar(
1802
                    $imageWebPath['email'],
1803
                    $gravatarSize,
1804
                    api_get_setting('gravatar_type')
1805
                );
1806
1807
                if ($addRandomId) {
1808
                    $file .= '&rand='.uniqid();
1809
                }
1810
1811
                return $file;
1812
            }
1813
1814
            return $anonymousPath;
1815
        }
1816
1817
        $pictureSysPath = self::get_user_picture_path_by_id($user_id, 'system');
1818
1819
        $file = $pictureSysPath['dir'].$realSizeName.$pictureWebFile;
1820
        $picture = '';
1821
        if (file_exists($file)) {
1822
            $picture = $pictureWebDir.$realSizeName.$pictureWebFile;
1823
        } else {
1824
            $file = $pictureSysPath['dir'].$pictureWebFile;
1825
            if (file_exists($file) && !is_dir($file)) {
1826
                $picture = $pictureWebFile['dir'].$pictureWebFile;
1827
            }
1828
        }
1829
1830
        if (empty($picture)) {
1831
            return $anonymousPath;
1832
        }
1833
1834
        if ($addRandomId) {
1835
            $picture .= '?rand='.uniqid();
1836
        }
1837
1838
        return $picture;
1839
    }
1840
1841
    /**
1842
     * Creates new user photos in various sizes of a user, or deletes user photos.
1843
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
1844
     * @param   int $user_id The user internal identification number.
1845
     * @param   string $file The common file name for the newly created photos.
1846
     *                       It will be checked and modified for compatibility with the file system.
1847
     *                       If full name is provided, path component is ignored.
1848
     *                       If an empty name is provided, then old user photos are deleted only,
1849
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1850
     * @param   string $source_file The full system name of the image from which user photos will be created.
1851
     * @param   string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1852
     * @return  mixed Returns the resulting common file name of created images which usually should be stored in database.
1853
     * When deletion is requested returns empty string. In case of internal error or negative validation returns FALSE.
1854
     */
1855
    public static function update_user_picture($user_id, $file = null, $source_file = null, $cropParameters = '')
1856
    {
1857
        if (empty($user_id)) {
1858
            return false;
1859
        }
1860
        $delete = empty($file);
1861
        if (empty($source_file)) {
1862
            $source_file = $file;
1863
        }
1864
1865
        // User-reserved directory where photos have to be placed.
1866
        $path_info = self::getUserPicturePathById($user_id, 'system');
1867
1868
        $path = $path_info['dir'];
1869
1870
        // If this directory does not exist - we create it.
1871
        if (!file_exists($path)) {
1872
            mkdir($path, api_get_permissions_for_new_directories(), true);
1873
        }
1874
1875
        // The old photos (if any).
1876
        $old_file = $path_info['file'];
1877
1878
        // Let us delete them.
1879 View Code Duplication
        if ($old_file != 'unknown.jpg') {
1880
            if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE) {
1881
                $prefix = 'saved_'.date('Y_m_d_H_i_s').'_'.uniqid('').'_';
1882
                @rename($path.'small_'.$old_file, $path.$prefix.'small_'.$old_file);
1883
                @rename($path.'medium_'.$old_file, $path.$prefix.'medium_'.$old_file);
1884
                @rename($path.'big_'.$old_file, $path.$prefix.'big_'.$old_file);
1885
                @rename($path.$old_file, $path.$prefix.$old_file);
1886
            } else {
1887
                @unlink($path.'small_'.$old_file);
1888
                @unlink($path.'medium_'.$old_file);
1889
                @unlink($path.'big_'.$old_file);
1890
                @unlink($path.$old_file);
1891
            }
1892
        }
1893
1894
        // Exit if only deletion has been requested. Return an empty picture name.
1895
        if ($delete) {
1896
            return '';
1897
        }
1898
1899
        // Validation 2.
1900
        $allowed_types = api_get_supported_image_extensions();
1901
        $file = str_replace('\\', '/', $file);
1902
        $filename = (($pos = strrpos($file, '/')) !== false) ? substr($file, $pos + 1) : $file;
1903
        $extension = strtolower(substr(strrchr($filename, '.'), 1));
1904
        if (!in_array($extension, $allowed_types)) {
1905
            return false;
1906
        }
1907
1908
        // This is the common name for the new photos.
1909
        if (KEEP_THE_NAME_WHEN_CHANGE_IMAGE && $old_file != 'unknown.jpg') {
1910
            $old_extension = strtolower(substr(strrchr($old_file, '.'), 1));
1911
            $filename = in_array($old_extension, $allowed_types) ? substr($old_file, 0, -strlen($old_extension)) : $old_file;
1912
            $filename = (substr($filename, -1) == '.') ? $filename.$extension : $filename.'.'.$extension;
1913
        } else {
1914
            $filename = api_replace_dangerous_char($filename);
1915
            if (PREFIX_IMAGE_FILENAME_WITH_UID) {
1916
                $filename = uniqid('').'_'.$filename;
1917
            }
1918
            // We always prefix user photos with user ids, so on setting
1919
            // api_get_setting('split_users_upload_directory') === 'true'
1920
            // the correspondent directories to be found successfully.
1921
            $filename = $user_id.'_'.$filename;
1922
        }
1923
1924
        //Crop the image to adjust 1:1 ratio
1925
        $image = new Image($source_file);
1926
        $image->crop($cropParameters);
1927
1928
        // Storing the new photos in 4 versions with various sizes.
1929
        $userPath = self::getUserPathById($user_id, 'system');
1930
1931
        // If this path does not exist - we create it.
1932
        if (!file_exists($userPath)) {
1933
            mkdir($userPath, api_get_permissions_for_new_directories(), true);
1934
        }
1935
        $small = new Image($source_file);
1936
        $small->resize(32);
1937
        $small->send_image($userPath.'small_'.$filename);
1938
        $medium = new Image($source_file);
1939
        $medium->resize(85);
1940
        $medium->send_image($userPath.'medium_'.$filename);
1941
        $normal = new Image($source_file);
1942
        $normal->resize(200);
1943
        $normal->send_image($userPath.$filename);
1944
1945
        $big = new Image($source_file); // This is the original picture.
1946
        $big->send_image($userPath.'big_'.$filename);
1947
1948
        $result = $small && $medium && $normal && $big;
1949
1950
        return $result ? $filename : false;
1951
    }
1952
1953
    /**
1954
     * Update User extra field file type into {user_folder}/{$extra_field}
1955
     * @param int $user_id          The user internal identification number
1956
     * @param string $extra_field   The $extra_field The extra field name
1957
     * @param null $file            The filename
1958
     * @param null $source_file     The temporal filename
1959
     * @return bool|null            return filename if success, but false
1960
     */
1961
    public static function update_user_extra_file($user_id, $extra_field = '', $file = null, $source_file = null)
1962
    {
1963
        // Add Filter
1964
        $source_file = Security::filter_filename($source_file);
1965
        $file = Security::filter_filename($file);
1966
1967
        if (empty($user_id)) {
1968
            return false;
1969
        }
1970
1971
        if (empty($source_file)) {
1972
            $source_file = $file;
1973
        }
1974
1975
        // User-reserved directory where extra file have to be placed.
1976
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1977
        $path = $path_info['dir'];
1978
        if (!empty($extra_field)) {
1979
            $path .= $extra_field.'/';
1980
        }
1981
        // If this directory does not exist - we create it.
1982
        if (!file_exists($path)) {
1983
            @mkdir($path, api_get_permissions_for_new_directories(), true);
1984
        }
1985
1986
        if (filter_extension($file)) {
1987
            if (@move_uploaded_file($source_file, $path.$file)) {
1988
                if ($extra_field) {
1989
                    return $extra_field.'/'.$file;
1990
                } else {
1991
                    return $file;
1992
                }
1993
            }
1994
        }
1995
        return false; // this should be returned if anything went wrong with the upload
1996
    }
1997
1998
1999
    /**
2000
     * Deletes user photos.
2001
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
2002
     * @param int $user_id            The user internal identification number.
2003
     * @return mixed            Returns empty string on success, FALSE on error.
2004
     */
2005
    public static function delete_user_picture($user_id)
2006
    {
2007
        return self::update_user_picture($user_id);
2008
    }
2009
2010
    /**
2011
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
2012
     * doesn't have any.
2013
     *
2014
     * If there has been a request to remove a production, the function will return
2015
     * without building the list unless forced to do so by the optional second
2016
     * parameter. This increases performance by avoiding to read through the
2017
     * productions on the filesystem before the removal request has been carried
2018
     * out because they'll have to be re-read afterwards anyway.
2019
     *
2020
     * @param   int $user_id    User id
2021
     * @param   bool $force    Optional parameter to force building after a removal request
2022
     * @param   bool $showDelete
2023
     *
2024
     * @return  string A string containing the XHTML code to display the production list, or FALSE
2025
     */
2026
    public static function build_production_list($user_id, $force = false, $showDelete = false)
2027
    {
2028
        if (!$force && !empty($_POST['remove_production'])) {
2029
2030
            return true; // postpone reading from the filesystem
2031
        }
2032
2033
        $productions = self::get_user_productions($user_id);
2034
2035
        if (empty($productions)) {
2036
2037
            return false;
2038
        }
2039
2040
        $production_dir = self::getUserPathById($user_id, 'web');
2041
        $del_image = Display::returnIconPath('delete.png');
2042
        $add_image = Display::returnIconPath('archive.png');
2043
        $del_text = get_lang('Delete');
2044
        $production_list = '';
2045
        if (count($productions) > 0) {
2046
            $production_list = '<div class="files-production"><ul id="productions">';
2047
            foreach ($productions as $file) {
2048
                $production_list .= '<li><img src="'.$add_image.'" /><a href="'.$production_dir.urlencode($file).'" target="_blank">'.htmlentities($file).'</a>';
2049 View Code Duplication
                if ($showDelete) {
2050
                    $production_list .= '&nbsp;&nbsp;<input style="width:16px;" type="image" name="remove_production['.urlencode($file).']" src="'.$del_image.'" alt="'.$del_text.'" title="'.$del_text.' '.htmlentities($file).'" onclick="javascript: return confirmation(\''.htmlentities($file).'\');" /></li>';
2051
                }
2052
            }
2053
            $production_list .= '</ul></div>';
2054
        }
2055
2056
        return $production_list;
2057
    }
2058
2059
    /**
2060
     * Returns an array with the user's productions.
2061
     *
2062
     * @param    $user_id    User id
2063
     * @return   array  An array containing the user's productions
2064
     */
2065
    public static function get_user_productions($user_id)
2066
    {
2067
        $production_repository = self::getUserPathById($user_id, 'system');
2068
        $productions = array();
2069
2070
        if (is_dir($production_repository)) {
2071
            $handle = opendir($production_repository);
2072
            while ($file = readdir($handle)) {
2073
                if ($file == '.' ||
2074
                    $file == '..' ||
2075
                    $file == '.htaccess' ||
2076
                    is_dir($production_repository.$file)
2077
                ) {
2078
                    // skip current/parent directory and .htaccess
2079
                    continue;
2080
                }
2081
2082
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
2083
                    // User's photos should not be listed as productions.
2084
                    continue;
2085
                }
2086
                $productions[] = $file;
2087
            }
2088
        }
2089
2090
        return $productions;
2091
    }
2092
2093
    /**
2094
     * Remove a user production.
2095
     *
2096
     * @param int $user_id        User id
2097
     * @param string $production    The production to remove
2098
     */
2099
    public static function remove_user_production($user_id, $production)
2100
    {
2101
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
2102
        $production_file = $production_path['dir'].$production;
2103
        if (is_file($production_file)) {
2104
            unlink($production_file);
2105
            return true;
2106
        }
2107
        return false;
2108
    }
2109
2110
    /**
2111
     * Update an extra field value for a given user
2112
     * @param    integer   $userId User ID
2113
     * @param    string    $variable Field variable name
2114
     * @param    string    $value Field value
2115
     *
2116
     * @return    boolean    true if field updated, false otherwise
2117
     */
2118 View Code Duplication
    public static function update_extra_field_value($userId, $variable, $value = '')
2119
    {
2120
        $extraFieldValue = new ExtraFieldValue('user');
2121
        $params = [
2122
            'item_id' => $userId,
2123
            'variable' => $variable,
2124
            'value' => $value
2125
        ];
2126
2127
        return $extraFieldValue->save($params);
2128
    }
2129
2130
    /**
2131
     * Get an array of extra fields with field details (type, default value and options)
2132
     * @param    integer    Offset (from which row)
2133
     * @param    integer    Number of items
2134
     * @param    integer    Column on which sorting is made
2135
     * @param    string    Sorting direction
2136
     * @param    boolean    Optional. Whether we get all the fields or just the visible ones
2137
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
2138
     * @return    array    Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
2139
     */
2140
    public static function get_extra_fields(
2141
        $from = 0,
2142
        $number_of_items = 0,
2143
        $column = 5,
2144
        $direction = 'ASC',
2145
        $all_visibility = true,
2146
        $field_filter = null
2147
    ) {
2148
        $fields = array();
2149
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2150
        $t_ufo = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
2151
        $columns = array(
2152
            'id',
2153
            'variable',
2154
            'field_type',
2155
            'display_text',
2156
            'default_value',
2157
            'field_order',
2158
            'filter'
2159
        );
2160
        $column = intval($column);
2161
        $sort_direction = '';
2162
        if (in_array(strtoupper($direction), array('ASC', 'DESC'))) {
2163
            $sort_direction = strtoupper($direction);
2164
        }
2165
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
2166
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
2167
        if (!$all_visibility) {
2168
            $sqlf .= " AND visible_to_self = 1 ";
2169
        }
2170
        if (!is_null($field_filter)) {
2171
            $field_filter = intval($field_filter);
2172
            $sqlf .= " AND filter = $field_filter ";
2173
        }
2174
        $sqlf .= " ORDER BY ".$columns[$column]." $sort_direction ";
2175
        if ($number_of_items != 0) {
2176
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
2177
        }
2178
        $resf = Database::query($sqlf);
2179
        if (Database::num_rows($resf) > 0) {
2180
            while ($rowf = Database::fetch_array($resf)) {
2181
                $fields[$rowf['id']] = array(
2182
                    0 => $rowf['id'],
2183
                    1 => $rowf['variable'],
2184
                    2 => $rowf['field_type'],
2185
                    3 => empty($rowf['display_text']) ? '' : $rowf['display_text'],
2186
                    4 => $rowf['default_value'],
2187
                    5 => $rowf['field_order'],
2188
                    6 => $rowf['visible_to_self'],
2189
                    7 => $rowf['changeable'],
2190
                    8 => $rowf['filter'],
2191
                    9 => array(),
2192
                    10 => '<a name="'.$rowf['id'].'"></a>',
2193
                );
2194
2195
                $sqlo = "SELECT * FROM $t_ufo
2196
                         WHERE field_id = ".$rowf['id']."
2197
                         ORDER BY option_order ASC";
2198
                $reso = Database::query($sqlo);
2199
                if (Database::num_rows($reso) > 0) {
2200
                    while ($rowo = Database::fetch_array($reso)) {
2201
                        $fields[$rowf['id']][9][$rowo['id']] = array(
2202
                            0 => $rowo['id'],
2203
                            1 => $rowo['option_value'],
2204
                            2 => empty($rowo['display_text']) ? '' : $rowo['display_text'],
2205
                            3 => $rowo['option_order']
2206
                        );
2207
                    }
2208
                }
2209
            }
2210
        }
2211
2212
        return $fields;
2213
    }
2214
2215
    /**
2216
     * Build a list of extra file already uploaded in $user_folder/{$extra_field}/
2217
     * @param $user_id
2218
     * @param $extra_field
2219
     * @param bool $force
2220
     * @param bool $showDelete
2221
     * @return bool|string
2222
     */
2223
    public static function build_user_extra_file_list($user_id, $extra_field, $force = false, $showDelete = false)
2224
    {
2225
        if (!$force && !empty($_POST['remove_'.$extra_field])) {
2226
            return true; // postpone reading from the filesystem
2227
        }
2228
2229
        $extra_files = self::get_user_extra_files($user_id, $extra_field);
2230
        if (empty($extra_files)) {
2231
            return false;
2232
        }
2233
2234
        $path_info = self::get_user_picture_path_by_id($user_id, 'web');
2235
        $path = $path_info['dir'];
2236
        $del_image = Display::returnIconPath('delete.png');
2237
2238
        $del_text = get_lang('Delete');
2239
        $extra_file_list = '';
2240
        if (count($extra_files) > 0) {
2241
            $extra_file_list = '<div class="files-production"><ul id="productions">';
2242
            foreach ($extra_files as $file) {
2243
                $filename = substr($file, strlen($extra_field) + 1);
2244
                $extra_file_list .= '<li>'.Display::return_icon('archive.png').'<a href="'.$path.$extra_field.'/'.urlencode($filename).'" target="_blank">'.htmlentities($filename).'</a> ';
2245 View Code Duplication
                if ($showDelete) {
2246
                    $extra_file_list .= '<input style="width:16px;" type="image" name="remove_extra_'.$extra_field.'['.urlencode($file).']" src="'.$del_image.'" alt="'.$del_text.'" title="'.$del_text.' '.htmlentities($filename).'" onclick="javascript: return confirmation(\''.htmlentities($filename).'\');" /></li>';
2247
                }
2248
            }
2249
            $extra_file_list .= '</ul></div>';
2250
        }
2251
2252
        return $extra_file_list;
2253
    }
2254
2255
    /**
2256
     * Get valid filenames in $user_folder/{$extra_field}/
2257
     * @param $user_id
2258
     * @param $extra_field
2259
     * @param bool $full_path
2260
     * @return array
2261
     */
2262
    public static function get_user_extra_files($user_id, $extra_field, $full_path = false)
2263
    {
2264
        if (!$full_path) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
2265
            // Nothing to do
2266
        } else {
2267
            $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2268
            $path = $path_info['dir'];
2269
        }
2270
        $extra_data = self::get_extra_user_data_by_field($user_id, $extra_field);
2271
        $extra_files = $extra_data[$extra_field];
2272
        if (is_array($extra_files)) {
2273
            foreach ($extra_files as $key => $value) {
2274
                if (!$full_path) {
2275
                    // Relative path from user folder
2276
                    $files[] = $value;
2277
                } else {
2278
                    $files[] = $path.$value;
2279
                }
2280
            }
2281
        } elseif (!empty($extra_files)) {
2282
            if (!$full_path) {
2283
                // Relative path from user folder
2284
                $files[] = $extra_files;
2285
            } else {
2286
                $files[] = $path.$extra_files;
2287
            }
2288
        }
2289
2290
        return $files; // can be an empty array
2291
    }
2292
2293
    /**
2294
     * Remove an {$extra_file} from the user folder $user_folder/{$extra_field}/
2295
     * @param $user_id
2296
     * @param $extra_field
2297
     * @param $extra_file
2298
     * @return bool
2299
     */
2300
    public static function remove_user_extra_file($user_id, $extra_field, $extra_file)
2301
    {
2302
        $extra_file = Security::filter_filename($extra_file);
2303
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2304
        if (strpos($extra_file, $extra_field) !== false) {
2305
            $path_extra_file = $path_info['dir'].$extra_file;
2306
        } else {
2307
            $path_extra_file = $path_info['dir'].$extra_field.'/'.$extra_file;
2308
        }
2309
        if (is_file($path_extra_file)) {
2310
            unlink($path_extra_file);
2311
            return true;
2312
        }
2313
        return false;
2314
    }
2315
2316
    /**
2317
     * Creates a new extra field
2318
     * @param    string    $variable Field's internal variable name
2319
     * @param    int       $fieldType  Field's type
2320
     * @param    string    $displayText Field's language var name
2321
     * @param    string    $default Field's default value
2322
     * @return int
2323
     */
2324 View Code Duplication
    public static function create_extra_field($variable, $fieldType, $displayText, $default)
2325
    {
2326
        $extraField = new ExtraField('user');
2327
        $params = [
2328
            'variable' => $variable,
2329
            'field_type' => $fieldType,
2330
            'display_text' => $displayText,
2331
            'default_value' => $default
2332
        ];
2333
2334
        return $extraField->save($params);
2335
    }
2336
2337
    /**
2338
     * Check if a field is available
2339
     * @param    string    $variable
2340
     * @return    boolean
2341
     */
2342
    public static function is_extra_field_available($variable)
2343
    {
2344
        $extraField = new ExtraField('user');
2345
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2346
2347
        return !empty($data) ? true : false;
2348
    }
2349
2350
    /**
2351
     * Gets user extra fields data
2352
     * @param    integer    User ID
2353
     * @param    boolean    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2354
     * @param    boolean    Whether to return invisible fields as well
2355
     * @param    boolean    Whether to split multiple-selection fields or not
2356
     * @return    array    Array of fields => value for the given user
2357
     */
2358
    public static function get_extra_user_data(
2359
        $user_id,
2360
        $prefix = false,
2361
        $all_visibility = true,
2362
        $splitmultiple = false,
2363
        $field_filter = null
2364
    ) {
2365
        // A sanity check.
2366 View Code Duplication
        if (empty($user_id)) {
2367
            $user_id = 0;
2368
        } else {
2369
            if ($user_id != strval(intval($user_id)))
2370
                return array();
2371
        }
2372
        $extra_data = array();
2373
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2374
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2375
        $user_id = intval($user_id);
2376
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2377
                FROM $t_uf f
2378
                WHERE
2379
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2380
                ";
2381
        $filter_cond = '';
2382
2383
        if (!$all_visibility) {
2384
            if (isset($field_filter)) {
2385
                $field_filter = intval($field_filter);
2386
                $filter_cond .= " AND filter = $field_filter ";
2387
            }
2388
            $sql .= " AND f.visible_to_self = 1 $filter_cond ";
2389
        } else {
2390
            if (isset($field_filter)) {
2391
                $field_filter = intval($field_filter);
2392
                $sql .= " AND filter = $field_filter ";
2393
            }
2394
        }
2395
2396
        $sql .= " ORDER BY f.field_order";
2397
2398
        $res = Database::query($sql);
2399
        if (Database::num_rows($res) > 0) {
2400
            while ($row = Database::fetch_array($res)) {
2401
                if ($row['type'] == self::USER_FIELD_TYPE_TAG) {
2402
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2403
                    $extra_data['extra_'.$row['fvar']] = $tags;
2404
                } else {
2405
                    $sqlu = "SELECT value as fval
2406
                            FROM $t_ufv
2407
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2408
                    $resu = Database::query($sqlu);
2409
                    // get default value
2410
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2411
                               WHERE id=".$row['id'];
2412
                    $res_df = Database::query($sql_df);
2413
2414
                    if (Database::num_rows($resu) > 0) {
2415
                        $rowu = Database::fetch_array($resu);
2416
                        $fval = $rowu['fval'];
2417
                        if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2418
                            $fval = explode(';', $rowu['fval']);
2419
                        }
2420
                    } else {
2421
                        $row_df = Database::fetch_array($res_df);
2422
                        $fval = $row_df['fval_df'];
2423
                    }
2424
                    // We get here (and fill the $extra_data array) even if there
2425
                    // is no user with data (we fill it with default values)
2426
                    if ($prefix) {
2427 View Code Duplication
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2428
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2429
                        } else {
2430
                            $extra_data['extra_'.$row['fvar']] = $fval;
2431
                        }
2432 View Code Duplication
                    } else {
2433
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2434
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2435
                        } else {
2436
                            $extra_data[$row['fvar']] = $fval;
2437
                        }
2438
                    }
2439
                }
2440
            }
2441
        }
2442
2443
        return $extra_data;
2444
    }
2445
2446
    /** Get extra user data by field
2447
     * @param int    user ID
2448
     * @param string the internal variable name of the field
2449
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2450
     */
2451
    public static function get_extra_user_data_by_field(
2452
        $user_id,
2453
        $field_variable,
2454
        $prefix = false,
2455
        $all_visibility = true,
2456
        $splitmultiple = false
2457
    ) {
2458
        // A sanity check.
2459 View Code Duplication
        if (empty($user_id)) {
2460
            $user_id = 0;
2461
        } else {
2462
            if ($user_id != strval(intval($user_id)))
2463
                return array();
2464
        }
2465
        $extra_data = array();
2466
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2467
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2468
        $user_id = intval($user_id);
2469
2470
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2471
                FROM $t_uf f
2472
                WHERE f.variable = '$field_variable' ";
2473
2474
        if (!$all_visibility) {
2475
            $sql .= " AND f.visible_to_self = 1 ";
2476
        }
2477
2478
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2479
2480
        $sql .= " ORDER BY f.field_order";
2481
2482
        $res = Database::query($sql);
2483
        if (Database::num_rows($res) > 0) {
2484
            while ($row = Database::fetch_array($res)) {
2485
                $sqlu = "SELECT value as fval FROM $t_ufv v INNER JOIN $t_uf f
2486
                         ON (v.field_id = f.id)
2487
                         WHERE
2488
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2489
                            field_id = ".$row['id']." AND
2490
                            item_id = ".$user_id;
2491
                $resu = Database::query($sqlu);
2492
                $fval = '';
2493 View Code Duplication
                if (Database::num_rows($resu) > 0) {
2494
                    $rowu = Database::fetch_array($resu);
2495
                    $fval = $rowu['fval'];
2496
                    if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2497
                        $fval = explode(';', $rowu['fval']);
2498
                    }
2499
                }
2500
                if ($prefix) {
2501
                    $extra_data['extra_'.$row['fvar']] = $fval;
2502
                } else {
2503
                    $extra_data[$row['fvar']] = $fval;
2504
                }
2505
            }
2506
        }
2507
2508
        return $extra_data;
2509
    }
2510
2511
    /**
2512
     * Get the extra field information for a certain field (the options as well)
2513
     * @param  int     $variable The name of the field we want to know everything about
2514
     * @return array   Array containing all the information about the extra profile field
2515
     * (first level of array contains field details, then 'options' sub-array contains options details,
2516
     * as returned by the database)
2517
     * @author Julio Montoya
2518
     * @since v1.8.6
2519
     */
2520
    public static function get_extra_field_information_by_name($variable)
2521
    {
2522
        $extraField = new ExtraField('user');
2523
2524
        return $extraField->get_handler_field_info_by_field_variable($variable);
2525
    }
2526
2527
    /**
2528
     * Get the extra field information for user tag (the options as well)
2529
     * @param  int     $variable The name of the field we want to know everything about
2530
     * @return array   Array containing all the information about the extra profile field
2531
     * (first level of array contains field details, then 'options' sub-array contains options details,
2532
     * as returned by the database)
2533
     * @author José Loguercio
2534
     * @since v1.11.0
2535
     */
2536
    public static function get_extra_field_tags_information_by_name($variable)
2537
    {
2538
        $extraField = new ExtraField('user');
2539
2540
        return $extraField->get_handler_field_info_by_tags($variable);
2541
    }
2542
2543
    /**
2544
     * @param string $type
2545
     *
2546
     * @return array
2547
     */
2548
    public static function get_all_extra_field_by_type($type)
2549
    {
2550
        $extraField = new ExtraField('user');
2551
2552
        return $extraField->get_all_extra_field_by_type($type);
2553
    }
2554
2555
    /**
2556
     * Get all the extra field information of a certain field (also the options)
2557
     *
2558
     * @param int $fieldId the ID of the field we want to know everything of
2559
     * @return array $return containing all th information about the extra profile field
2560
     * @author Julio Montoya
2561
     * @deprecated
2562
     * @since v1.8.6
2563
     */
2564
    public static function get_extra_field_information($fieldId)
2565
    {
2566
        $extraField = new ExtraField('user');
2567
2568
        return $extraField->getFieldInfoByFieldId($fieldId);
2569
    }
2570
2571
    /**
2572
     * Get extra user data by value
2573
     * @param string $variable the internal variable name of the field
2574
     * @param string $value the internal value of the field
2575
     * @param bool $all_visibility
2576
     *
2577
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2578
     */
2579
     public static function get_extra_user_data_by_value($variable, $value, $all_visibility = true)
2580
    {
2581
        $extraFieldValue = new ExtraFieldValue('user');
2582
        $extraField = new ExtraField('user');
2583
2584
        $info = $extraField->get_handler_field_info_by_field_variable($variable);
2585
2586
        if (false === $info) {
2587
            return [];
2588
        }
2589
2590
        $data = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
2591
            $variable,
2592
            $value,
2593
            false,
2594
            false,
2595
            true
2596
        );
2597
2598
        $result = [];
2599
        if (!empty($data)) {
2600
            foreach ($data as $item) {
2601
                $result[] = $item['item_id'];
2602
            }
2603
        }
2604
2605
        return $result;
2606
    }
2607
2608
    /**
2609
     * Get extra user data by tags value
2610
     *
2611
     * @param int $fieldId the ID of the field we want to know everything of
2612
     * @param string $tag the tag name for search
2613
     * @return array with extra data info of a user
2614
     * @author José Loguercio
2615
     * @since v1.11.0
2616
     */
2617
    public static function get_extra_user_data_by_tags($fieldId, $tag)
2618
    {
2619
        $extraField = new ExtraField('user');
2620
        $result = $extraField->getAllUserPerTag($fieldId, $tag);
2621
        $array = [];
2622
        foreach ($result as $index => $user) {
2623
            $array[] = $user['user_id'];
2624
        }
2625
        return $array;
2626
    }
2627
2628
    /**
2629
     * Get extra user data by field variable
2630
     * @param string    $variable field variable
2631
     * @return array    data
2632
     */
2633
    public static function get_extra_user_data_by_field_variable($variable)
2634
    {
2635
        $extra_information_by_variable = self::get_extra_field_information_by_name($variable);
2636
        $field_id = intval($extra_information_by_variable['id']);
2637
2638
        $extraField = new ExtraFieldValue('user');
2639
        $data = $extraField->getValuesByFieldId($field_id);
2640
2641
        if (!empty($data) > 0) {
2642
            foreach ($data as $row) {
0 ignored issues
show
Bug introduced by
The expression $data of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
2643
                $user_id = $row['item_id'];
2644
                $data[$user_id] = $row;
2645
            }
2646
        }
2647
2648
        return $data;
2649
    }
2650
2651
    /**
2652
     * Get extra user data tags by field variable
2653
     *
2654
     * @param string $variable field variable
2655
     * @return array
2656
     */
2657
    public static function get_extra_user_data_for_tags($variable)
2658
    {
2659
        $data = self::get_extra_field_tags_information_by_name($variable);
2660
2661
        return $data;
2662
    }
2663
2664
    /**
2665
     * Gives a list of [session_category][session_id] for the current user.
2666
     * @param integer $user_id
2667
     * @param boolean $is_time_over whether to fill the first element or not (to give space for courses out of categories)
2668
     * @param boolean $ignore_visibility_for_admins optional true if limit time from session is over, false otherwise
2669
     * @param boolean $ignoreTimeLimit ignore time start/end
2670
     * @return array  list of statuses [session_category][session_id]
2671
     *
2672
     * @todo ensure multiple access urls are managed correctly
2673
     */
2674
    public static function get_sessions_by_category(
2675
        $user_id,
2676
        $is_time_over = true,
2677
        $ignore_visibility_for_admins = false,
2678
        $ignoreTimeLimit = false
2679
    ) {
2680
        if ($user_id != strval(intval($user_id))) {
2681
            return array();
2682
        }
2683
2684
        // Get the list of sessions per user
2685
        $now = new DateTime('now', new DateTimeZone('UTC'));
2686
2687
        $dql = "SELECT DISTINCT
2688
                    s.id,
2689
                    s.name,
2690
                    s.accessStartDate AS access_start_date,
2691
                    s.accessEndDate AS access_end_date,
2692
                    sc.id AS session_category_id,
2693
                    sc.name AS session_category_name,
2694
                    sc.dateStart AS session_category_date_start,
2695
                    sc.dateEnd AS session_category_date_end,
2696
                    s.coachAccessStartDate AS coach_access_start_date,
2697
                    s.coachAccessEndDate AS coach_access_end_date
2698
                FROM ChamiloCoreBundle:Session AS s
2699
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser AS scu WITH scu.session = s
2700
                INNER JOIN ChamiloCoreBundle:AccessUrlRelSession AS url WITH url.session = s
2701
                LEFT JOIN ChamiloCoreBundle:SessionCategory AS sc WITH s.category = sc
2702
                WHERE (scu.user = :user OR s.generalCoach = :user) AND url.url = :url
2703
                ORDER BY sc.name, s.name";
2704
2705
        $dql = Database::getManager()
2706
            ->createQuery($dql)
2707
            ->setParameters(
2708
                ['user' => $user_id, 'url' => api_get_current_access_url_id()]
2709
            )
2710
        ;
2711
2712
        $sessionData = $dql->getResult();
2713
        $categories = [];
2714
2715
        foreach ($sessionData as $row) {
2716
            $session_id = $row['id'];
2717
            $coachList = SessionManager::getCoachesBySession($session_id);
2718
2719
            $categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
2720
            $categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
2721
2722
            $courseList = self::get_courses_list_by_session(
2723
                $user_id,
2724
                $session_id
2725
            );
2726
2727
            // User portal filters:
2728
            if ($ignoreTimeLimit === false) {
2729
                if ($is_time_over) {
2730
                    // History
2731
                    if (empty($row['access_end_date'])) {
2732
                        continue;
2733
                    } else {
2734
                        if ($row['access_end_date'] > $now) {
2735
                            continue;
2736
                        }
2737
                    }
2738
                } else {
2739
                    // Current user portal
2740
                    $isGeneralCoach = SessionManager::user_is_general_coach($user_id, $row['id']);
2741
                    $isCoachOfCourse = in_array($user_id, $coachList);
2742
2743
                    if (api_is_platform_admin() || $isGeneralCoach || $isCoachOfCourse) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
2744
                        // Teachers can access the session depending in the access_coach date
2745
                    } else {
2746
                        if (isset($row['access_end_date']) &&
2747
                            !empty($row['access_end_date'])
2748
                        ) {
2749
                            if ($row['access_end_date'] <= $now) {
2750
                                continue;
2751
                            }
2752
                        }
2753
                    }
2754
                }
2755
            }
2756
2757
            $categories[$row['session_category_id']]['session_category'] = array(
2758
                'id' => $row['session_category_id'],
2759
                'name' => $row['session_category_name'],
2760
                'date_start' => $categoryStart,
2761
                'date_end' => $categoryEnd
2762
            );
2763
2764
            $visibility = api_get_session_visibility(
2765
                $session_id,
2766
                null,
2767
                $ignore_visibility_for_admins
2768
            );
2769
2770 View Code Duplication
            if ($visibility != SESSION_VISIBLE) {
2771
                // Course Coach session visibility.
2772
                $blockedCourseCount = 0;
2773
                $closedVisibilityList = array(
2774
                    COURSE_VISIBILITY_CLOSED,
2775
                    COURSE_VISIBILITY_HIDDEN
2776
                );
2777
2778
                foreach ($courseList as $course) {
2779
                    // Checking session visibility
2780
                    $sessionCourseVisibility = api_get_session_visibility(
2781
                        $session_id,
2782
                        $course['real_id'],
2783
                        $ignore_visibility_for_admins
2784
                    );
2785
2786
                    $courseIsVisible = !in_array(
2787
                        $course['visibility'],
2788
                        $closedVisibilityList
2789
                    );
2790
                    if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
2791
                        $blockedCourseCount++;
2792
                    }
2793
                }
2794
2795
                // If all courses are blocked then no show in the list.
2796
                if ($blockedCourseCount === count($courseList)) {
2797
                    $visibility = SESSION_INVISIBLE;
2798
                } else {
2799
                    $visibility = $sessionCourseVisibility;
2800
                }
2801
            }
2802
2803
            switch ($visibility) {
2804
                case SESSION_VISIBLE_READ_ONLY:
2805
                case SESSION_VISIBLE:
2806
                case SESSION_AVAILABLE:
2807
                    break;
2808
                case SESSION_INVISIBLE:
2809
                    if ($ignore_visibility_for_admins === false) {
2810
                        continue 2;
2811
                    }
2812
            }
2813
2814
            $categories[$row['session_category_id']]['sessions'][$row['id']] = array(
2815
                'session_name' => $row['name'],
2816
                'session_id' => $row['id'],
2817
                'access_start_date' => $row['access_start_date'] ? $row['access_start_date']->format('Y-m-d H:i:s') : null,
2818
                'access_end_date' => $row['access_end_date'] ? $row['access_end_date']->format('Y-m-d H:i:s') : null,
2819
                'coach_access_start_date' => $row['coach_access_start_date'] ? $row['coach_access_start_date']->format('Y-m-d H:i:s') : null,
2820
                'coach_access_end_date' => $row['coach_access_end_date'] ? $row['coach_access_end_date']->format('Y-m-d H:i:s') : null,
2821
                'display_start_date' => $row['display_start_date'] ? $row['display_start_date']->format(
2822
                    'Y-m-d H:i:s'
2823
                ) : null,
2824
                'display_end_date' => $row['display_end_date'] ? $row['display_end_date']->format(
2825
                    'Y-m-d H:i:s'
2826
                ) : null,
2827
                'courses' => $courseList
2828
            );
2829
        }
2830
2831
        return $categories;
2832
    }
2833
2834
    /**
2835
     * Gives a list of [session_id-course_code] => [status] for the current user.
2836
     * @param integer $user_id
2837
     * @param int $sessionLimit
2838
     * @return array  list of statuses (session_id-course_code => status)
2839
     */
2840
    public static function get_personal_session_course_list($user_id, $sessionLimit = null)
2841
    {
2842
        // Database Table Definitions
2843
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2844
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2845
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2846
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2847
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2848
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2849
2850
        if ($user_id != strval(intval($user_id))) {
2851
            return array();
2852
        }
2853
2854
        // We filter the courses from the URL
2855
        $join_access_url = $where_access_url = '';
2856
2857
        if (api_get_multiple_access_url()) {
2858
            $access_url_id = api_get_current_access_url_id();
2859
            if ($access_url_id != -1) {
2860
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2861
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2862
                $where_access_url = " AND access_url_id = $access_url_id ";
2863
            }
2864
        }
2865
2866
        // Courses in which we subscribed out of any session
2867
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
2868
2869
        $sql = "SELECT
2870
                    course.code,
2871
                    course_rel_user.status course_rel_status,
2872
                    course_rel_user.sort sort,
2873
                    course_rel_user.user_course_cat user_course_cat
2874
                 FROM $tbl_course_user course_rel_user
2875
                 LEFT JOIN $tbl_course course
2876
                 ON course.id = course_rel_user.c_id
2877
                 LEFT JOIN $tbl_user_course_category user_course_category
2878
                 ON course_rel_user.user_course_cat = user_course_category.id
2879
                 $join_access_url
2880
                 WHERE
2881
                    course_rel_user.user_id = '".$user_id."' AND
2882
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2883
                    $where_access_url
2884
                 ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
2885
2886
        $course_list_sql_result = Database::query($sql);
2887
2888
        $personal_course_list = array();
2889
        if (Database::num_rows($course_list_sql_result) > 0) {
2890
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2891
                $course_info = api_get_course_info($result_row['code']);
2892
                $result_row['course_info'] = $course_info;
2893
                $personal_course_list[] = $result_row;
2894
            }
2895
        }
2896
2897
        $coachCourseConditions = null;
2898
2899
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2900
        if (api_is_allowed_to_create_course()) {
2901
            $sessionListFromCourseCoach = array();
2902
            $sql = " SELECT DISTINCT session_id
2903
                    FROM $tbl_session_course_user
2904
                    WHERE user_id = $user_id AND status = 2 ";
2905
2906
            $result = Database::query($sql);
2907
            if (Database::num_rows($result)) {
2908
                $result = Database::store_result($result);
2909
                foreach ($result as $session) {
2910
                    $sessionListFromCourseCoach[] = $session['session_id'];
2911
                }
2912
            }
2913
            if (!empty($sessionListFromCourseCoach)) {
2914
                $condition = implode("','", $sessionListFromCourseCoach);
2915
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2916
            }
2917
        }
2918
2919
        // Get the list of sessions where the user is subscribed
2920
        // This is divided into two different queries
2921
        $sessions = array();
2922
2923
        $sessionLimitRestriction = '';
2924
        if (!empty($sessionLimit)) {
2925
            $sessionLimit = (int) $sessionLimit;
2926
            $sessionLimitRestriction = "LIMIT $sessionLimit";
2927
        }
2928
2929
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2930
                FROM $tbl_session_user su INNER JOIN $tbl_session s
2931
                ON (s.id = su.session_id)
2932
                WHERE (
2933
                    su.user_id = $user_id AND
2934
                    su.relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2935
                )
2936
                $coachCourseConditions
2937
                ORDER BY access_start_date, access_end_date, name
2938
                $sessionLimitRestriction
2939
        ";
2940
2941
        $result = Database::query($sql);
2942 View Code Duplication
        if (Database::num_rows($result) > 0) {
2943
            while ($row = Database::fetch_assoc($result)) {
2944
                $sessions[$row['id']] = $row;
2945
            }
2946
        }
2947
2948
        $sql = "SELECT DISTINCT
2949
                id, name, access_start_date, access_end_date
2950
                FROM $tbl_session s
2951
                WHERE (
2952
                    id_coach = $user_id
2953
                )
2954
                $coachCourseConditions
2955
                ORDER BY access_start_date, access_end_date, name";
2956
2957
        $result = Database::query($sql);
2958
        if (Database::num_rows($result) > 0) {
2959
            while ($row = Database::fetch_assoc($result)) {
2960
                if (empty($sessions[$row['id']])) {
2961
                    $sessions[$row['id']] = $row;
2962
                }
2963
            }
2964
        }
2965
2966
        if (api_is_allowed_to_create_course()) {
2967
            foreach ($sessions as $enreg) {
2968
                $session_id = $enreg['id'];
2969
                $session_visibility = api_get_session_visibility($session_id);
2970
2971
                if ($session_visibility == SESSION_INVISIBLE) {
2972
                    continue;
2973
                }
2974
2975
                // This query is horribly slow when more than a few thousand
2976
                // users and just a few sessions to which they are subscribed
2977
                $sql = "SELECT DISTINCT
2978
                        course.code code,
2979
                        course.title i,
2980
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
2981
                        email, course.course_language l,
2982
                        1 sort,
2983
                        category_code user_course_cat,
2984
                        access_start_date,
2985
                        access_end_date,
2986
                        session.id as session_id,
2987
                        session.name as session_name
2988
                    FROM $tbl_session_course_user as session_course_user
2989
                        INNER JOIN $tbl_course AS course
2990
                            ON course.id = session_course_user.c_id
2991
                        INNER JOIN $tbl_session as session
2992
                            ON session.id = session_course_user.session_id
2993
                        LEFT JOIN $tbl_user as user
2994
                            ON user.id = session_course_user.user_id OR session.id_coach = user.id
2995
                    WHERE
2996
                        session_course_user.session_id = $session_id AND (
2997
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
2998
                            OR session.id_coach = $user_id
2999
                        )
3000
                    ORDER BY i";
3001
                $course_list_sql_result = Database::query($sql);
3002 View Code Duplication
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3003
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
3004
                    $key = $result_row['session_id'].' - '.$result_row['code'];
3005
                    $personal_course_list[$key] = $result_row;
3006
                }
3007
            }
3008
        }
3009
3010
        foreach ($sessions as $enreg) {
3011
            $session_id = $enreg['id'];
3012
            $session_visibility = api_get_session_visibility($session_id);
3013
            if ($session_visibility == SESSION_INVISIBLE) {
3014
                continue;
3015
            }
3016
3017
            /* This query is very similar to the above query,
3018
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
3019
            $sql = "SELECT DISTINCT
3020
                course.code code,
3021
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
3022
                email,
3023
                course.course_language l,
3024
                1 sort,
3025
                category_code user_course_cat,
3026
                access_start_date,
3027
                access_end_date,
3028
                session.id as session_id,
3029
                session.name as session_name,
3030
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
3031
            FROM $tbl_session_course_user as session_course_user
3032
            INNER JOIN $tbl_course AS course
3033
            ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
3034
            INNER JOIN $tbl_session as session 
3035
            ON session_course_user.session_id = session.id
3036
            LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
3037
            WHERE session_course_user.user_id = $user_id
3038
            ORDER BY i";
3039
3040
            $course_list_sql_result = Database::query($sql);
3041 View Code Duplication
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3042
                $result_row['course_info'] = api_get_course_info($result_row['code']);
3043
                $key = $result_row['session_id'].' - '.$result_row['code'];
3044
                if (!isset($personal_course_list[$key])) {
3045
                    $personal_course_list[$key] = $result_row;
3046
                }
3047
            }
3048
        }
3049
3050
        return $personal_course_list;
3051
    }
3052
3053
    /**
3054
     * Gives a list of courses for the given user in the given session
3055
     * @param integer $user_id
3056
     * @param integer $session_id
3057
     * @return array  list of statuses (session_id-course_code => status)
3058
     */
3059
    public static function get_courses_list_by_session($user_id, $session_id)
3060
    {
3061
        // Database Table Definitions
3062
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3063
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
3064
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3065
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3066
3067
        $user_id = intval($user_id);
3068
        $session_id = intval($session_id);
3069
        //we filter the courses from the URL
3070
        $join_access_url = $where_access_url = '';
3071
3072
        if (api_get_multiple_access_url()) {
3073
            $urlId = api_get_current_access_url_id();
3074
            if ($urlId != -1) {
3075
                $tbl_url_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3076
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
3077
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
3078
            }
3079
        }
3080
3081
        /* This query is very similar to the query below, but it will check the
3082
        session_rel_course_user table if there are courses registered
3083
        to our user or not */
3084
        $sql = "SELECT DISTINCT
3085
                    c.visibility,
3086
                    c.id as real_id,
3087
                    c.code as course_code,
3088
                    sc.position
3089
                FROM $tbl_session_course_user as scu
3090
                INNER JOIN $tbl_session_course sc
3091
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3092
                INNER JOIN $tableCourse as c
3093
                ON (scu.c_id = c.id)
3094
                $join_access_url
3095
                WHERE
3096
                    scu.user_id = $user_id AND
3097
                    scu.session_id = $session_id
3098
                    $where_access_url
3099
                ORDER BY sc.position ASC, c.id";
3100
3101
        $personal_course_list = array();
3102
        $courses = array();
3103
3104
        $result = Database::query($sql);
3105 View Code Duplication
        if (Database::num_rows($result) > 0) {
3106
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3107
                $result_row['status'] = 5;
3108
                if (!in_array($result_row['real_id'], $courses)) {
3109
                    $personal_course_list[] = $result_row;
3110
                    $courses[] = $result_row['real_id'];
3111
                }
3112
            }
3113
        }
3114
3115
        if (api_is_allowed_to_create_course()) {
3116
            $sql = "SELECT DISTINCT
3117
                        c.visibility, 
3118
                        c.id as real_id,
3119
                        c.code as course_code,
3120
                        sc.position
3121
                    FROM $tbl_session_course_user as scu
3122
                    INNER JOIN $tbl_session as s
3123
                    ON (scu.session_id = s.id)
3124
                    INNER JOIN $tbl_session_course sc
3125
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3126
                    INNER JOIN $tableCourse as c
3127
                    ON (scu.c_id = c.id)
3128
                    $join_access_url
3129
                    WHERE
3130
                      s.id = $session_id AND
3131
                      (
3132
                        (scu.user_id = $user_id AND scu.status = 2) OR
3133
                        s.id_coach = $user_id
3134
                      )
3135
                    $where_access_url
3136
                    ORDER BY sc.position ASC";
3137
            $result = Database::query($sql);
3138
3139 View Code Duplication
            if (Database::num_rows($result) > 0) {
3140
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3141
                    $result_row['status'] = 2;
3142
                    if (!in_array($result_row['real_id'], $courses)) {
3143
                        $personal_course_list[] = $result_row;
3144
                        $courses[] = $result_row['real_id'];
3145
                    }
3146
                }
3147
            }
3148
        }
3149
3150
        if (api_is_drh()) {
3151
            $sessionList = SessionManager::get_sessions_followed_by_drh($user_id);
3152
            $sessionList = array_keys($sessionList);
3153
            if (in_array($session_id, $sessionList)) {
3154
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3155 View Code Duplication
                if (!empty($courseList)) {
3156
                    foreach ($courseList as $course) {
0 ignored issues
show
Bug introduced by
The expression $courseList of type integer|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
3157
                        if (!in_array($course['id'], $courses)) {
3158
                            $personal_course_list[] = $course;
3159
                        }
3160
                    }
3161
                }
3162
            }
3163
        } else {
3164
            //check if user is general coach for this session
3165
            $sessionInfo = api_get_session_info($session_id);
3166
            if ($sessionInfo['id_coach'] == $user_id) {
3167
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3168 View Code Duplication
                if (!empty($courseList)) {
3169
                    foreach ($courseList as $course) {
0 ignored issues
show
Bug introduced by
The expression $courseList of type integer|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
3170
                        if (!in_array($course['id'], $courses)) {
3171
                            $personal_course_list[] = $course;
3172
                        }
3173
                    }
3174
                }
3175
            }
3176
        }
3177
3178
        return $personal_course_list;
3179
    }
3180
3181
    /**
3182
     * Get user id from a username
3183
     * @param    string    $username
3184
     * @return    int        User ID (or false if not found)
3185
     */
3186
    public static function get_user_id_from_username($username)
3187
    {
3188
        if (empty($username)) {
3189
3190
            return false;
3191
        }
3192
        $username = trim($username);
3193
        $username = Database::escape_string($username);
3194
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
3195
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
3196
        $res = Database::query($sql);
3197
3198
        if ($res === false) {
3199
            return false;
3200
        }
3201
        if (Database::num_rows($res) !== 1) {
3202
            return false;
3203
        }
3204
        $row = Database::fetch_array($res);
3205
3206
        return $row['id'];
3207
    }
3208
3209
    /**
3210
     * Get the users files upload from his share_folder
3211
     * @param    string  $user_id   User ID
3212
     * @param   string  $course course directory
3213
     * @param   string  $resourcetype resourcetype: images, all
3214
     * @return    int        User ID (or false if not found)
3215
     */
3216
    public static function get_user_upload_files_by_course($user_id, $course, $resourcetype = 'all')
3217
    {
3218
        $return = '';
3219
        if (!empty($user_id) && !empty($course)) {
3220
            $user_id = intval($user_id);
3221
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3222
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3223
            $file_list = array();
3224
3225
            if (is_dir($path)) {
3226
                $handle = opendir($path);
3227
                while ($file = readdir($handle)) {
3228
                    if ($file == '.' || $file == '..' || $file == '.htaccess' || is_dir($path.$file)) {
3229
                        continue; // skip current/parent directory and .htaccess
3230
                    }
3231
                    $file_list[] = $file;
3232
                }
3233
                if (count($file_list) > 0) {
3234
                    $return = "<h4>$course</h4>";
3235
                    $return .= '<ul class="thumbnails">';
3236
                }
3237
                $extensionList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif'];
3238
                foreach ($file_list as $file) {
3239
                    if ($resourcetype == "all") {
3240
                        $return .= '<li><a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
3241
                    } elseif ($resourcetype == "images") {
3242
                        //get extension
3243
                        $ext = explode('.', $file);
3244
                        if (isset($ext[1]) && in_array($ext[1], $extensionList)) {
3245
                            $return .= '<li class="span2">
3246
                                            <a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
3247
                                                <img src="'.$web_path.urlencode($file).'" >
3248
                                            </a>
3249
                                        </li>';
3250
                        }
3251
                    }
3252
                }
3253
                if (count($file_list) > 0) {
3254
                    $return .= '</ul>';
3255
                }
3256
            }
3257
        }
3258
3259
        return $return;
3260
    }
3261
3262
    /**
3263
     * Gets the API key (or keys) and return them into an array
3264
     * @param   int     Optional user id (defaults to the result of api_get_user_id())
3265
     * @return  array   Non-indexed array containing the list of API keys for this user, or FALSE on error
3266
     */
3267
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
3268
    {
3269
        if ($user_id != strval(intval($user_id)))
3270
            return false;
3271
        if (empty($user_id)) {
3272
            $user_id = api_get_user_id();
3273
        }
3274
        if ($user_id === false)
3275
            return false;
3276
        $service_name = Database::escape_string($api_service);
3277
        if (is_string($service_name) === false) {
3278
            return false;
3279
        }
3280
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3281
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
3282
        $res = Database::query($sql);
3283
        if ($res === false)
3284
            return false; //error during query
3285
        $num = Database::num_rows($res);
3286
        if ($num == 0)
3287
            return false;
3288
        $list = array();
3289
        while ($row = Database::fetch_array($res)) {
3290
            $list[$row['id']] = $row['api_key'];
3291
        }
3292
        return $list;
3293
    }
3294
3295
    /**
3296
     * Adds a new API key to the users' account
3297
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
3298
     * @return  boolean True on success, false on failure
3299
     */
3300
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
3301
    {
3302
        if ($user_id != strval(intval($user_id)))
3303
            return false;
3304
        if (empty($user_id)) {
3305
            $user_id = api_get_user_id();
3306
        }
3307
        if ($user_id === false)
3308
            return false;
3309
        $service_name = Database::escape_string($api_service);
3310
        if (is_string($service_name) === false) {
3311
            return false;
3312
        }
3313
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3314
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
3315
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
3316
        $res = Database::query($sql);
3317
        if ($res === false)
3318
            return false; //error during query
3319
        $num = Database::insert_id();
3320
        return ($num == 0) ? false : $num;
3321
    }
3322
3323
    /**
3324
     * Deletes an API key from the user's account
3325
     * @param   int     API key's internal ID
3326
     * @return  boolean True on success, false on failure
3327
     */
3328
    public static function delete_api_key($key_id)
3329
    {
3330
        if ($key_id != strval(intval($key_id)))
3331
            return false;
3332
        if ($key_id === false)
3333
            return false;
3334
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3335
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
3336
        $res = Database::query($sql);
3337
        if ($res === false)
3338
            return false; //error during query
3339
        $num = Database::num_rows($res);
3340
        if ($num !== 1)
3341
            return false;
3342
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
3343
        $res = Database::query($sql);
3344
        if ($res === false)
3345
            return false; //error during query
3346
        return true;
3347
    }
3348
3349
    /**
3350
     * Regenerate an API key from the user's account
3351
     * @param   int     user ID (defaults to the results of api_get_user_id())
3352
     * @param   string  API key's internal ID
3353
     * @return  int        num
3354
     */
3355
    public static function update_api_key($user_id, $api_service)
3356
    {
3357
        if ($user_id != strval(intval($user_id)))
3358
            return false;
3359
        if ($user_id === false)
3360
            return false;
3361
        $service_name = Database::escape_string($api_service);
3362
        if (is_string($service_name) === false) {
3363
            return false;
3364
        }
3365
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3366
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3367
        $res = Database::query($sql);
3368
        $num = Database::num_rows($res);
3369
        if ($num == 1) {
3370
            $id_key = Database::fetch_array($res, 'ASSOC');
3371
            self::delete_api_key($id_key['id']);
3372
            $num = self::add_api_key($user_id, $api_service);
3373
        } elseif ($num == 0) {
3374
            $num = self::add_api_key($user_id, $api_service);
3375
        }
3376
        return $num;
3377
    }
3378
3379
    /**
3380
     * @param   int     user ID (defaults to the results of api_get_user_id())
3381
     * @param   string    API key's internal ID
3382
     * @return  int    row ID, or return false if not found
3383
     */
3384
    public static function get_api_key_id($user_id, $api_service)
3385
    {
3386
        if ($user_id != strval(intval($user_id)))
3387
            return false;
3388
        if ($user_id === false)
3389
            return false;
3390
        if (empty($api_service))
3391
            return false;
3392
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3393
        $api_service = Database::escape_string($api_service);
3394
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3395
        $res = Database::query($sql);
3396
        if (Database::num_rows($res) < 1) {
3397
            return false;
3398
        }
3399
        $row = Database::fetch_array($res, 'ASSOC');
3400
        return $row['id'];
3401
    }
3402
3403
    /**
3404
     * Checks if a user_id is platform admin
3405
     * @param   int user ID
3406
     * @return  boolean True if is admin, false otherwise
3407
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3408
     */
3409 View Code Duplication
    public static function is_admin($user_id)
3410
    {
3411
        if (empty($user_id) || $user_id != strval(intval($user_id))) {
3412
            return false;
3413
        }
3414
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3415
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3416
        $res = Database::query($sql);
3417
3418
        return Database::num_rows($res) === 1;
3419
    }
3420
3421
    /**
3422
     * Get the total count of users
3423
     * @param   int     Status of users to be counted
3424
     * @param   int     Access URL ID (optional)
3425
     * @return    mixed    Number of users or false on error
3426
     */
3427
    public static function get_number_of_users($status = 0, $access_url_id = null)
3428
    {
3429
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3430
        $t_a = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
3431
        $sql = "SELECT count(*) FROM $t_u u";
3432
        $sql2 = '';
3433
        if (is_int($status) && $status > 0) {
3434
            $sql2 .= " WHERE u.status = $status ";
3435
        }
3436
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
3437
            $sql .= ", $t_a a ";
3438
            $sql2 .= " AND a.access_url_id = $access_url_id AND u.id = a.user_id ";
3439
        }
3440
        $sql = $sql.$sql2;
3441
        $res = Database::query($sql);
3442
        if (Database::num_rows($res) === 1) {
3443
            return (int) Database::result($res, 0, 0);
3444
        }
3445
        return false;
3446
    }
3447
3448
    /**
3449
     * @author Isaac flores <[email protected]>
3450
     * @param string The email administrator
3451
     * @param integer The user id
3452
     * @param string The message title
3453
     * @param string The content message
3454
     */
3455
    public static function send_message_in_outbox($email_administrator, $user_id, $title, $content)
3456
    {
3457
        $table_message = Database::get_main_table(TABLE_MESSAGE);
3458
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3459
        $title = api_utf8_decode($title);
3460
        $content = api_utf8_decode($content);
3461
        $email_administrator = Database::escape_string($email_administrator);
3462
        //message in inbox
3463
        $sql_message_outbox = 'SELECT id from '.$table_user.' WHERE email="'.$email_administrator.'" ';
3464
        //$num_row_query = Database::num_rows($sql_message_outbox);
3465
        $res_message_outbox = Database::query($sql_message_outbox);
3466
        $array_users_administrator = array();
3467
        while ($row_message_outbox = Database::fetch_array($res_message_outbox, 'ASSOC')) {
3468
            $array_users_administrator[] = $row_message_outbox['id'];
3469
        }
3470
        //allow to insert messages in outbox
3471
        for ($i = 0; $i < count($array_users_administrator); $i++) {
3472
            $sql_insert_outbox = "INSERT INTO $table_message(user_sender_id, user_receiver_id, msg_status, send_date, title, content ) ".
3473
                " VALUES (".
3474
                "'".(int) $user_id."', '".(int) ($array_users_administrator[$i])."', '4', '".api_get_utc_datetime()."','".Database::escape_string($title)."','".Database::escape_string($content)."'".
3475
                ")";
3476
            Database::query($sql_insert_outbox);
3477
        }
3478
    }
3479
3480
    /**
3481
     *
3482
     * Gets the tags of a specific field_id
3483
     * USER TAGS
3484
     *
3485
     * Instructions to create a new user tag by Julio Montoya <[email protected]>
3486
     *
3487
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible.
3488
     *    Called it "books" for example.
3489
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3490
     * 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
3491
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3492
     * 5. Test and enjoy.
3493
     *
3494
     * @param string $tag
3495
     * @param int $field_id field_id
3496
     * @param string $return_format how we are going to result value in array or in a string (json)
3497
     * @param $limit
3498
     *
3499
     * @return mixed
3500
     *
3501
     */
3502
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3503
    {
3504
        // database table definition
3505
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3506
        $field_id = intval($field_id);
3507
        $limit = intval($limit);
3508
        $tag = trim(Database::escape_string($tag));
3509
3510
        // all the information of the field
3511
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3512
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3513
        $result = Database::query($sql);
3514
        $return = array();
3515 View Code Duplication
        if (Database::num_rows($result) > 0) {
3516
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3517
                $return[] = array('id' => $row['tag'], 'text' => $row['tag']);
3518
            }
3519
        }
3520
        if ($return_format === 'json') {
3521
            $return = json_encode($return);
3522
        }
3523
3524
        return $return;
3525
    }
3526
3527
    /**
3528
     * @param int $field_id
3529
     * @param int $limit
3530
     *
3531
     * @return array
3532
     */
3533
    public static function get_top_tags($field_id, $limit = 100)
3534
    {
3535
        // database table definition
3536
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3537
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3538
        $field_id = intval($field_id);
3539
        $limit = intval($limit);
3540
        // all the information of the field
3541
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3542
                INNER JOIN $table_user_tag ut
3543
                ON(ut.id = uv.tag_id)
3544
                WHERE field_id = $field_id
3545
                GROUP BY tag_id
3546
                ORDER BY count DESC
3547
                LIMIT $limit";
3548
        $result = Database::query($sql);
3549
        $return = array();
3550
        if (Database::num_rows($result) > 0) {
3551
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3552
                $return[] = $row;
3553
            }
3554
        }
3555
        return $return;
3556
    }
3557
3558
    /**
3559
     * Get user's tags
3560
     * @param int $user_id
3561
     * @param int $field_id
3562
     *
3563
     * @return array
3564
     */
3565
    public static function get_user_tags($user_id, $field_id)
3566
    {
3567
        // database table definition
3568
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3569
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3570
        $field_id = intval($field_id);
3571
        $user_id = intval($user_id);
3572
3573
        // all the information of the field
3574
        $sql = "SELECT ut.id, tag, count
3575
                FROM $table_user_tag ut
3576
                INNER JOIN $table_user_tag_values uv
3577
                ON (uv.tag_id=ut.ID)
3578
                WHERE field_id = $field_id AND user_id = $user_id
3579
                ORDER BY tag";
3580
        $result = Database::query($sql);
3581
        $return = array();
3582 View Code Duplication
        if (Database::num_rows($result) > 0) {
3583
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3584
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3585
            }
3586
        }
3587
3588
        return $return;
3589
    }
3590
3591
    /**
3592
     * Get user's tags
3593
     * @param int $user_id
3594
     * @param int $field_id
3595
     * @param bool $show_links show links or not
3596
     *
3597
     * @return array
3598
     */
3599
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3600
    {
3601
        // database table definition
3602
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3603
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3604
        $field_id = intval($field_id);
3605
        $user_id = intval($user_id);
3606
3607
        // all the information of the field
3608
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3609
                INNER JOIN $table_user_tag_values uv
3610
                ON (uv.tag_id = ut.id)
3611
                WHERE field_id = $field_id AND user_id = $user_id
3612
                ORDER BY tag";
3613
3614
        $result = Database::query($sql);
3615
        $return = array();
3616 View Code Duplication
        if (Database::num_rows($result) > 0) {
3617
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3618
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3619
            }
3620
        }
3621
        $user_tags = $return;
3622
        $tag_tmp = array();
3623
        foreach ($user_tags as $tag) {
3624
            if ($show_links) {
3625
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.$tag['tag'].'</a>';
3626
            } else {
3627
                $tag_tmp[] = $tag['tag'];
3628
            }
3629
        }
3630
3631
        if (is_array($user_tags) && count($user_tags) > 0) {
3632
            $return = implode(', ', $tag_tmp);
3633
        } else {
3634
3635
            return '';
3636
        }
3637
3638
        return $return;
3639
    }
3640
3641
    /**
3642
     * Get the tag id
3643
     * @param int $tag
3644
     * @param int $field_id
3645
     * @return int returns 0 if fails otherwise the tag id
3646
     */
3647
    public static function get_tag_id($tag, $field_id)
3648
    {
3649
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3650
        $tag = Database::escape_string($tag);
3651
        $field_id = intval($field_id);
3652
        //with COLLATE latin1_bin to select query in a case sensitive mode
3653
        $sql = "SELECT id FROM $table_user_tag
3654
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3655
        $result = Database::query($sql);
3656
        if (Database::num_rows($result) > 0) {
3657
            $row = Database::fetch_array($result, 'ASSOC');
3658
3659
            return $row['id'];
3660
        } else {
3661
3662
            return 0;
3663
        }
3664
    }
3665
3666
    /**
3667
     * Get the tag id
3668
     * @param int $tag_id
3669
     * @param int $field_id
3670
     *
3671
     * @return int 0 if fails otherwise the tag id
3672
     */
3673 View Code Duplication
    public static function get_tag_id_from_id($tag_id, $field_id)
3674
    {
3675
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3676
        $tag_id = intval($tag_id);
3677
        $field_id = intval($field_id);
3678
        $sql = "SELECT id FROM $table_user_tag
3679
                WHERE id = '$tag_id' AND field_id = $field_id";
3680
        $result = Database::query($sql);
3681
        if (Database::num_rows($result) > 0) {
3682
            $row = Database::fetch_array($result, 'ASSOC');
3683
            return $row['id'];
3684
        } else {
3685
            return false;
3686
        }
3687
    }
3688
3689
    /**
3690
     * Adds a user-tag value
3691
     * @param mixed $tag
3692
     * @param int $user_id
3693
     * @param int $field_id field id of the tag
3694
     * @return bool
3695
     */
3696
    public static function add_tag($tag, $user_id, $field_id)
3697
    {
3698
        // database table definition
3699
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3700
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3701
        $tag = trim(Database::escape_string($tag));
3702
        $user_id = intval($user_id);
3703
        $field_id = intval($field_id);
3704
3705
        $tag_id = self::get_tag_id($tag, $field_id);
3706
3707
        /* IMPORTANT
3708
         *  @todo we don't create tags with numbers
3709
         *
3710
         */
3711
        if (is_numeric($tag)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3712
            //the form is sending an id this means that the user select it from the list so it MUST exists
3713
            /* $new_tag_id = self::get_tag_id_from_id($tag,$field_id);
3714
              if ($new_tag_id !== false) {
3715
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3716
              $result = Database::query($sql);
3717
              $last_insert_id = $new_tag_id;
3718
              } else {
3719
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3720
              $result = Database::query($sql);
3721
              $last_insert_id = Database::insert_id();
3722
              } */
3723
        }
3724
3725
        //this is a new tag
3726
        if ($tag_id == 0) {
3727
            //the tag doesn't exist
3728
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3729
             Database::query($sql);
3730
            $last_insert_id = Database::insert_id();
3731
        } else {
3732
            //the tag exists we update it
3733
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3734
             Database::query($sql);
3735
            $last_insert_id = $tag_id;
3736
        }
3737
3738
        if (!empty($last_insert_id) && ($last_insert_id != 0)) {
3739
            //we insert the relationship user-tag
3740
            $sql = "SELECT tag_id FROM $table_user_tag_values
3741
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3742
            $result = Database::query($sql);
3743
            //if the relationship does not exist we create it
3744
            if (Database::num_rows($result) == 0) {
3745
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3746
                Database::query($sql);
3747
            }
3748
        }
3749
    }
3750
3751
    /**
3752
     * Deletes an user tag
3753
     * @param int $user_id
3754
     * @param int $field_id
3755
     *
3756
     */
3757
    public static function delete_user_tags($user_id, $field_id)
3758
    {
3759
        // database table definition
3760
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3761
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3762
        $tags = self::get_user_tags($user_id, $field_id);
3763
        if (is_array($tags) && count($tags) > 0) {
3764
            foreach ($tags as $key => $tag) {
3765
                if ($tag['count'] > '0') {
3766
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3767
                    Database::query($sql);
3768
                }
3769
                $sql = "DELETE FROM $table_user_tag_values
3770
                        WHERE user_id = $user_id AND tag_id = $key";
3771
                Database::query($sql);
3772
            }
3773
        }
3774
    }
3775
3776
    /**
3777
     * Process the tag list comes from the UserManager::update_extra_field_value() function
3778
     * @param array $tags the tag list that will be added
3779
     * @param int $user_id
3780
     * @param int $field_id
3781
     *
3782
     * @return bool
3783
     */
3784
    public static function process_tags($tags, $user_id, $field_id)
3785
    {
3786
        // We loop the tags and add it to the DB
3787
        if (is_array($tags)) {
3788
            foreach ($tags as $tag) {
3789
                self::add_tag($tag, $user_id, $field_id);
3790
            }
3791
        } else {
3792
            self::add_tag($tags, $user_id, $field_id);
3793
        }
3794
3795
        return true;
3796
    }
3797
3798
    /**
3799
     * Returns a list of all administrators
3800
     *
3801
     * @return array
3802
     */
3803
    public static function get_all_administrators()
3804
    {
3805
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3806
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3807
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3808
        $access_url_id = api_get_current_access_url_id();
3809
        if (api_get_multiple_access_url()) {
3810
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3811
                    FROM $tbl_url_rel_user as url
3812
                    INNER JOIN $table_admin as admin
3813
                    ON (admin.user_id=url.user_id)
3814
                    INNER JOIN $table_user u
3815
                    ON (u.id=admin.user_id)
3816
                    WHERE access_url_id ='".$access_url_id."'";
3817
        } else {
3818
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3819
                    FROM $table_admin as admin
3820
                    INNER JOIN $table_user u
3821
                    ON (u.id=admin.user_id)";
3822
        }
3823
        $result = Database::query($sql);
3824
        $return = array();
3825
        if (Database::num_rows($result) > 0) {
3826
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3827
                $return[$row['user_id']] = $row;
3828
            }
3829
        }
3830
3831
        return $return;
3832
    }
3833
3834
    /**
3835
     * Search an user (tags, first name, last name and email )
3836
     * @param string $tag
3837
     * @param int $field_id field id of the tag
3838
     * @param int $from where to start in the query
3839
     * @param int $number_of_items
3840
     * @param bool $getCount get count or not
3841
     * @return array
3842
     */
3843
    public static function get_all_user_tags(
3844
        $tag,
3845
        $field_id = 0,
3846
        $from = 0,
3847
        $number_of_items = 10,
3848
        $getCount = false
3849
    ) {
3850
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3851
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3852
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3853
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3854
3855
        $field_id = intval($field_id);
3856
        $from = intval($from);
3857
        $number_of_items = intval($number_of_items);
3858
3859
        $where_field = "";
3860
        $where_extra_fields = self::get_search_form_where_extra_fields();
3861
        if ($field_id != 0) {
3862
            $where_field = " field_id = $field_id AND ";
3863
        }
3864
3865
        // all the information of the field
3866
3867
        if ($getCount) {
3868
            $select = "SELECT count(DISTINCT u.id) count";
3869
        } else {
3870
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3871
        }
3872
3873
        $sql = " $select
3874
                FROM $user_table u
3875
                INNER JOIN $access_url_rel_user_table url_rel_user
3876
                ON (u.id = url_rel_user.user_id)
3877
                LEFT JOIN $table_user_tag_values uv
3878
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3879
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3880
                WHERE
3881
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3882
                    (
3883
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3884
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3885
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3886
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3887
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3888
                     )
3889
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3890
                     AND url_rel_user.access_url_id=".api_get_current_access_url_id();
3891
3892
        $keyword_active = true;
3893
        // only active users
3894
        if ($keyword_active) {
3895
            $sql .= " AND u.active='1'";
3896
        }
3897
        // avoid anonymous
3898
        $sql .= " AND u.status <> 6 ";
3899
        $sql .= " ORDER BY username";
3900
        $sql .= " LIMIT $from , $number_of_items";
3901
3902
        $result = Database::query($sql);
3903
        $return = array();
3904
3905
        if (Database::num_rows($result) > 0) {
3906
            if ($getCount) {
3907
                $row = Database::fetch_array($result, 'ASSOC');
3908
                return $row['count'];
3909
            }
3910
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3911
                if (isset($return[$row['id']]) &&
3912
                    !empty($return[$row['id']]['tag'])
3913
                ) {
3914
                    $url = Display::url(
3915
                        $row['tag'],
3916
                        api_get_path(WEB_PATH).'main/social/search.php?q='.$row['tag'],
3917
                        array('class' => 'tag')
3918
                    );
3919
                    $row['tag'] = $url;
3920
                }
3921
                $return[$row['id']] = $row;
3922
            }
3923
        }
3924
3925
        return $return;
3926
    }
3927
3928
    /**
3929
      * Get extra filtrable user fields (only type select)
3930
      * @return array
3931
      */
3932
    public static function get_extra_filtrable_fields()
3933
    {
3934
        $extraFieldList = self::get_extra_fields();
3935
3936
        $extraFiltrableFields = array();
3937 View Code Duplication
        if (is_array($extraFieldList)) {
3938
            foreach ($extraFieldList as $extraField) {
3939
                // If is enabled to filter and is a "<select>" field type
3940
                if ($extraField[8] == 1 && $extraField[2] == 4) {
3941
                    $extraFiltrableFields[] = array(
3942
                        'name' => $extraField[3],
3943
                        'variable' => $extraField[1],
3944
                        'data' => $extraField[9]
3945
                    );
3946
                }
3947
            }
3948
        }
3949
3950
        if (is_array($extraFiltrableFields) && count($extraFiltrableFields) > 0) {
3951
            return $extraFiltrableFields;
3952
        }
3953
    }
3954
3955
    /**
3956
      * Get extra where clauses for finding users based on extra filtrable user fields (type select)
3957
      * @return string With AND clauses based on user's ID which have the values to search in extra user fields
3958
      */
3959
    public static function get_search_form_where_extra_fields()
3960
    {
3961
        $useExtraFields = false;
3962
        $extraFields = self::get_extra_filtrable_fields();
3963
        $extraFieldResult = array();
3964 View Code Duplication
        if (is_array($extraFields) && count($extraFields) > 0) {
3965
            foreach ($extraFields as $extraField) {
3966
                $varName = 'field_'.$extraField['variable'];
3967
                if (self::is_extra_field_available($extraField['variable'])) {
3968
                    if (isset($_GET[$varName]) && $_GET[$varName] != '0') {
3969
                        $useExtraFields = true;
3970
                        $extraFieldResult[] = self::get_extra_user_data_by_value(
3971
                            $extraField['variable'],
3972
                            $_GET[$varName]
3973
                        );
3974
                    }
3975
                }
3976
            }
3977
        }
3978
3979
        if ($useExtraFields) {
3980
            $finalResult = array();
3981
            if (count($extraFieldResult) > 1) {
3982
                for ($i = 0; $i < count($extraFieldResult) - 1; $i++) {
3983
                if (is_array($extraFieldResult[$i]) && is_array($extraFieldResult[$i + 1])) {
3984
                        $finalResult = array_intersect($extraFieldResult[$i], $extraFieldResult[$i + 1]);
3985
                    }
3986
                }
3987
            } else {
3988
                $finalResult = $extraFieldResult[0];
3989
            }
3990
3991
            if (is_array($finalResult) && count($finalResult) > 0) {
3992
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
3993
            } else {
3994
                //no results
3995
                $whereFilter = " AND u.id  = -1 ";
3996
            }
3997
3998
            return $whereFilter;
3999
        }
4000
    }
4001
4002
    /**
4003
     * Show the search form
4004
     * @param string $query the value of the search box
4005
     * @return string HTML form
4006
     */
4007
    public static function get_search_form($query, $defaultParams = [])
4008
    {
4009
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
4010
        $form = new FormValidator(
4011
            'search_user',
4012
            'get',
4013
            api_get_path(WEB_PATH).'main/social/search.php',
4014
            '',
4015
            array(),
4016
            FormValidator::LAYOUT_HORIZONTAL
4017
        );
4018
4019
        $form->addText('q', get_lang('UsersGroups'), false, array(
4020
            "id" => "q"
4021
        ));
4022
        $options = array(
4023
            0 => get_lang('Select'),
4024
            1 => get_lang('User'),
4025
            2 => get_lang('Group'),
4026
        );
4027
        $form->addSelect(
4028
            'search_type',
4029
            get_lang('Type'),
4030
            $options,
4031
            array('onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type')
4032
        );
4033
4034
        // Extra fields
4035
4036
        $extraFields = self::get_extra_filtrable_fields();
4037
        $defaults = [];
4038
        if (is_array($extraFields) && count($extraFields) > 0) {
4039
            foreach ($extraFields as $extraField) {
4040
                $varName = 'field_'.$extraField['variable'];
4041
4042
                $options = [
4043
                    0 => get_lang('Select')
4044
                ];
4045
                foreach ($extraField['data'] as $option) {
4046
                    $checked = '';
4047
                    if (isset($_GET[$varName])) {
4048
                        if ($_GET[$varName] == $option[1]) {
4049
                            $defaults[$option[1]] = true;
4050
                        }
4051
                    }
4052
4053
                    $options[$option[1]] = $option[1];
4054
                }
4055
                $form->addSelect($varName, $extraField['name'], $options);
4056
            }
4057
        }
4058
4059
        $defaults['search_type'] = intval($searchType);
4060
        $defaults['q'] = api_htmlentities(Security::remove_XSS($query));
4061
4062
        if (!empty($defaultParams)) {
4063
            $defaults = array_merge($defaults, $defaultParams);
4064
        }
4065
        $form->setDefaults($defaults);
4066
4067
        $form->addButtonSearch(get_lang('Search'));
4068
4069
        $js = '<script>
4070
        extra_field_toogle();
4071
        function extra_field_toogle() {
4072
            if (jQuery("select[name=search_type]").val() != "1") { jQuery(".extra_field").hide(); } else { jQuery(".extra_field").show(); }
4073
        }
4074
        </script>';
4075
4076
        return $js.$form->returnForm();
4077
    }
4078
4079
    /**
4080
     * Shows the user menu
4081
     */
4082
    public static function show_menu()
4083
    {
4084
        echo '<div class="actions">';
4085
        echo '<a href="/main/auth/profile.php">'.Display::return_icon('profile.png').' '.get_lang('PersonalData').'</a>';
4086
        echo '<a href="/main/messages/inbox.php">'.Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
4087
        echo '<a href="/main/messages/outbox.php">'.Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
4088
        echo '<span style="float:right; padding-top:7px;">'.
4089
        '<a href="/main/auth/profile.php?show=1">'.Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
4090
        '</span>';
4091
        echo '</div>';
4092
    }
4093
4094
    /**
4095
     * Allow to register contact to social network
4096
     * @param int $friend_id user friend id
4097
     * @param int $my_user_id user id
4098
     * @param int $relation_type relation between users see constants definition
4099
     */
4100
    public static function relate_users($friend_id, $my_user_id, $relation_type)
4101
    {
4102
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4103
4104
        $friend_id = intval($friend_id);
4105
        $my_user_id = intval($my_user_id);
4106
        $relation_type = intval($relation_type);
4107
4108
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4109
                WHERE
4110
                    friend_user_id='.$friend_id.' AND
4111
                    user_id='.$my_user_id.' AND
4112
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
4113
        $result = Database::query($sql);
4114
        $row = Database::fetch_array($result, 'ASSOC');
4115
        $current_date = api_get_utc_datetime();
4116
4117
        if ($row['count'] == 0) {
4118
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4119
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4120
            Database::query($sql);
4121
            return true;
4122
        }
4123
4124
        $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
4125
                WHERE
4126
                    friend_user_id='.$friend_id.' AND
4127
                    user_id='.$my_user_id.' AND
4128
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
4129
        $result = Database::query($sql);
4130
        $row = Database::fetch_array($result, 'ASSOC');
4131
4132
        if ($row['count'] == 1) {
4133
            //only for the case of a RRHH
4134
            if ($row['relation_type'] != $relation_type && $relation_type == USER_RELATION_TYPE_RRHH) {
4135
                $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4136
                        VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4137
            } else {
4138
                $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
4139
                        WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
4140
            }
4141
            Database::query($sql);
4142
4143
            return true;
4144
        }
4145
4146
        return false;
4147
    }
4148
4149
    /**
4150
     * Deletes a contact
4151
     * @param int user friend id
4152
     * @param bool true will delete ALL friends relationship from $friend_id
4153
     * @author isaac flores paz <[email protected]>
4154
     * @author Julio Montoya <[email protected]> Cleaning code
4155
     */
4156
    public static function remove_user_rel_user($friend_id, $real_removed = false, $with_status_condition = '')
4157
    {
4158
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4159
        $tbl_my_message = Database::get_main_table(TABLE_MESSAGE);
4160
        $friend_id = intval($friend_id);
4161
4162
        if ($real_removed) {
4163
            $extra_condition = '';
4164
            if ($with_status_condition != '') {
4165
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
4166
            }
4167
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4168
                    WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND friend_user_id='.$friend_id.' '.$extra_condition;
4169
            Database::query($sql);
4170
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4171
                   WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND user_id='.$friend_id.' '.$extra_condition;
4172
            Database::query($sql);
4173
        } else {
4174
            $user_id = api_get_user_id();
4175
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4176
                    WHERE
4177
                        user_id='.$user_id.' AND
4178
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
4179
                        friend_user_id='.$friend_id;
4180
            $result = Database::query($sql);
4181
            $row = Database::fetch_array($result, 'ASSOC');
4182
            if ($row['count'] == 1) {
4183
                //Delete user rel user
4184
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
4185
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
4186
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4187
                          WHERE user_receiver_id='.$user_id.' AND user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
4188
                //Delete user
4189
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
4190
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
4191
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4192
                           WHERE user_receiver_id='.$friend_id.' AND user_sender_id='.$user_id.' AND update_date="0000-00-00 00:00:00" ';
4193
                Database::query($sql_i);
4194
                Database::query($sql_j);
4195
                Database::query($sql_ij);
4196
                Database::query($sql_ji);
4197
            }
4198
        }
4199
    }
4200
4201
    /**
4202
     * @param int $userId
4203
     * @return array
4204
     */
4205
    public static function getDrhListFromUser($userId)
4206
    {
4207
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4208
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4209
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4210
        $userId = intval($userId);
4211
4212
        $orderBy = null;
4213
        if (api_is_western_name_order()) {
4214
            $orderBy .= " ORDER BY firstname, lastname ";
4215
        } else {
4216
            $orderBy .= " ORDER BY lastname, firstname ";
4217
        }
4218
4219
        $sql = "SELECT u.id, username, u.firstname, u.lastname
4220
                FROM $tblUser u
4221
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
4222
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
4223
                WHERE
4224
                    access_url_id = ".api_get_current_access_url_id()." AND
4225
                    uru.user_id = '$userId' AND
4226
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4227
                $orderBy
4228
                ";
4229
        $result = Database::query($sql);
4230
4231
        return Database::store_result($result);
4232
    }
4233
4234
    /**
4235
     * get users followed by human resource manager
4236
     * @param int $userId
4237
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
4238
     * @param bool $getOnlyUserId
4239
     * @param bool $getSql
4240
     * @param bool $getCount
4241
     * @param int $from
4242
     * @param int $numberItems
4243
     * @param int $column
4244
     * @param string $direction
4245
     * @param int $active
4246
     * @param string $lastConnectionDate
4247
     * @return array     users
4248
     */
4249 View Code Duplication
    public static function get_users_followed_by_drh(
4250
        $userId,
4251
        $userStatus = 0,
4252
        $getOnlyUserId = false,
4253
        $getSql = false,
4254
        $getCount = false,
4255
        $from = null,
4256
        $numberItems = null,
4257
        $column = null,
4258
        $direction = null,
4259
        $active = null,
4260
        $lastConnectionDate = null
4261
    ) {
4262
        return self::getUsersFollowedByUser(
4263
            $userId,
4264
            $userStatus,
4265
            $getOnlyUserId,
4266
            $getSql,
4267
            $getCount,
4268
            $from,
4269
            $numberItems,
4270
            $column,
4271
            $direction,
4272
            $active,
4273
            $lastConnectionDate,
4274
            DRH
4275
        );
4276
    }
4277
4278
    /**
4279
    * Get users followed by human resource manager
4280
    * @param int $userId
4281
    * @param int  $userStatus Filter users by status (STUDENT, COURSEMANAGER, etc)
4282
    * @param bool $getOnlyUserId
4283
    * @param bool $getSql
4284
    * @param bool $getCount
4285
    * @param int $from
4286
    * @param int $numberItems
4287
    * @param int $column
4288
    * @param string $direction
4289
    * @param int $active
4290
    * @param string $lastConnectionDate
4291
    * @param int $status the function is called by who? COURSEMANAGER, DRH?
4292
    * @param string $keyword
4293
     *
4294
    * @return array user list
4295
    */
4296
    public static function getUsersFollowedByUser(
4297
        $userId,
4298
        $userStatus = null,
4299
        $getOnlyUserId = false,
4300
        $getSql = false,
4301
        $getCount = false,
4302
        $from = null,
4303
        $numberItems = null,
4304
        $column = null,
4305
        $direction = null,
4306
        $active = null,
4307
        $lastConnectionDate = null,
4308
        $status = null,
4309
        $keyword = null
4310
    ) {
4311
        // Database Table Definitions
4312
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4313
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4314
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4315
4316
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4317
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4318
4319
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4320
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4321
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4322
4323
        $userId = intval($userId);
4324
4325
        $limitCondition = '';
4326
4327 View Code Duplication
        if (isset($from) && isset($numberItems)) {
4328
            $from = intval($from);
4329
            $numberItems = intval($numberItems);
4330
            $limitCondition = "LIMIT $from, $numberItems";
4331
        }
4332
4333
        $column = Database::escape_string($column);
4334
        $direction = in_array(strtolower($direction), array('asc', 'desc')) ? $direction : null;
4335
4336
        $userConditions = '';
4337
        if (!empty($userStatus)) {
4338
            $userConditions .= ' AND u.status = '.intval($userStatus);
4339
        }
4340
4341
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
4342
        if ($getOnlyUserId) {
4343
            $select = " SELECT DISTINCT u.id user_id";
4344
        }
4345
4346
        $masterSelect = "SELECT DISTINCT * FROM ";
4347
4348
        if ($getCount) {
4349
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
4350
            $select = " SELECT DISTINCT(u.id) user_id";
4351
        }
4352
4353
        if (!is_null($active)) {
4354
            $active = intval($active);
4355
            $userConditions .= " AND u.active = $active ";
4356
        }
4357
4358 View Code Duplication
        if (!empty($keyword)) {
4359
            $keyword = Database::escape_string($keyword);
4360
            $userConditions .= " AND (
4361
                u.username LIKE '%$keyword%' OR
4362
                u.firstname LIKE '%$keyword%' OR
4363
                u.lastname LIKE '%$keyword%' OR
4364
                u.official_code LIKE '%$keyword%' OR
4365
                u.email LIKE '%$keyword%'
4366
            )";
4367
        }
4368
4369
        if (!empty($lastConnectionDate)) {
4370
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
4371
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
4372
        }
4373
4374
        $courseConditions = null;
4375
        $sessionConditionsCoach = null;
4376
        $sessionConditionsTeacher = null;
4377
        $drhConditions = null;
4378
        $teacherSelect = null;
4379
4380
        switch ($status) {
4381
            case DRH:
4382
                $drhConditions .= " AND
4383
                    friend_user_id = '$userId' AND
4384
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4385
                ";
4386
                break;
4387
            case COURSEMANAGER:
4388
                $drhConditions .= " AND
4389
                    friend_user_id = '$userId' AND
4390
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4391
                ";
4392
4393
                $sessionConditionsCoach .= " AND
4394
                    (s.id_coach = '$userId')
4395
                ";
4396
4397
                $sessionConditionsTeacher .= " AND
4398
                    (scu.status = 2 AND scu.user_id = '$userId')
4399
                ";
4400
4401
                $teacherSelect =
4402
                "UNION ALL (
4403
                        $select
4404
                        FROM $tbl_user u
4405
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4406
                        WHERE
4407
                            (
4408
                                sru.session_id IN (
4409
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4410
                                    $tbl_session_rel_access_url session_rel_access_rel_user
4411
                                    ON session_rel_access_rel_user.session_id = s.id
4412
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4413
                                    $sessionConditionsCoach                                  
4414
                                ) OR sru.session_id IN (
4415
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4416
                                    INNER JOIN $tbl_session_rel_access_url url
4417
                                    ON (url.session_id = s.id)
4418
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4419
                                    ON (scu.session_id = s.id)
4420
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4421
                                    $sessionConditionsTeacher
4422
                                )
4423
                            )                            
4424
                            $userConditions
4425
                    )
4426
                    UNION ALL(
4427
                        $select
4428
                        FROM $tbl_user u
4429
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4430
                        WHERE cu.c_id IN (
4431
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4432
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4433
                        )
4434
                        $userConditions
4435
                    )"
4436
                ;
4437
                break;
4438
            case STUDENT_BOSS:
4439
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4440
                break;
4441
        }
4442
4443
        $join = null;
4444
        $sql = " $masterSelect
4445
                (
4446
                    (
4447
                        $select
4448
                        FROM $tbl_user u
4449
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4450
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4451
                        $join
4452
                        WHERE
4453
                            access_url_id = ".api_get_current_access_url_id()."
4454
                            $drhConditions
4455
                            $userConditions
4456
                    )
4457
                    $teacherSelect
4458
4459
                ) as t1";
4460
4461
        if ($getSql) {
4462
            return $sql;
4463
        }
4464 View Code Duplication
        if ($getCount) {
4465
            $result = Database::query($sql);
4466
            $row = Database::fetch_array($result);
4467
            return $row['count'];
4468
        }
4469
4470
        $orderBy = null;
4471
        if ($getOnlyUserId == false) {
4472
            if (api_is_western_name_order()) {
4473
                $orderBy .= " ORDER BY firstname, lastname ";
4474
            } else {
4475
                $orderBy .= " ORDER BY lastname, firstname ";
4476
            }
4477
4478 View Code Duplication
            if (!empty($column) && !empty($direction)) {
4479
                // Fixing order due the UNIONs
4480
                $column = str_replace('u.', '', $column);
4481
                $orderBy = " ORDER BY $column $direction ";
4482
            }
4483
        }
4484
4485
        $sql .= $orderBy;
4486
        $sql .= $limitCondition;
4487
4488
        $result = Database::query($sql);
4489
        $users = array();
4490
        if (Database::num_rows($result) > 0) {
4491
4492
            while ($row = Database::fetch_array($result)) {
4493
                $users[$row['user_id']] = $row;
4494
            }
4495
        }
4496
4497
        return $users;
4498
    }
4499
4500
    /**
4501
     * Subscribes users to human resource manager (Dashboard feature)
4502
     * @param   int    $hr_dept_id
4503
     * @param   array   $users_id
4504
     * @param   int     affected rows
4505
     * */
4506
    public static function subscribeUsersToHRManager($hr_dept_id, $users_id)
4507
    {
4508
        return self::subscribeUsersToUser($hr_dept_id, $users_id, USER_RELATION_TYPE_RRHH);
4509
    }
4510
4511
    /**
4512
     * Add subscribed users to a user by relation type
4513
     * @param int $userId The user id
4514
     * @param array $subscribedUsersId The id of suscribed users
4515
     * @param string $relationType The relation type
4516
     * @param bool $deleteUsersBeforeInsert
4517
     */
4518
    public static function subscribeUsersToUser($userId, $subscribedUsersId, $relationType, $deleteUsersBeforeInsert = false)
4519
    {
4520
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4521
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4522
4523
        $userId = intval($userId);
4524
        $relationType = intval($relationType);
4525
        $affectedRows = 0;
4526
4527
        if (api_get_multiple_access_url()) {
4528
            // Deleting assigned users to hrm_id
4529
            $sql = "SELECT s.user_id FROM $userRelUserTable s 
4530
                    INNER JOIN $userRelAccessUrlTable a ON (a.user_id = s.user_id) 
4531
                    WHERE 
4532
                        friend_user_id = $userId AND 
4533
                        relation_type = $relationType AND 
4534
                        access_url_id = ".api_get_current_access_url_id();
4535
        } else {
4536
            $sql = "SELECT user_id FROM $userRelUserTable 
4537
                    WHERE friend_user_id = $userId 
4538
                    AND relation_type = $relationType";
4539
        }
4540
        $result = Database::query($sql);
4541
4542 View Code Duplication
        if (Database::num_rows($result) > 0) {
4543
            while ($row = Database::fetch_array($result)) {
4544
                $sql = "DELETE FROM $userRelUserTable 
4545
                        WHERE 
4546
                          user_id = {$row['user_id']} AND 
4547
                          friend_user_id = $userId AND 
4548
                          relation_type = $relationType";
4549
                Database::query($sql);
4550
            }
4551
        }
4552
4553
        if ($deleteUsersBeforeInsert) {
4554
            $sql = "DELETE FROM $userRelUserTable 
4555
                    WHERE 
4556
                        user_id = $userId AND
4557
                        relation_type = $relationType";
4558
            Database::query($sql);
4559
        }
4560
4561
        // Inserting new user list
4562
        if (is_array($subscribedUsersId)) {
4563
            foreach ($subscribedUsersId as $subscribedUserId) {
4564
                $subscribedUserId = intval($subscribedUserId);
4565
4566
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4567
                        VALUES ($subscribedUserId, $userId, $relationType)";
4568
4569
                $result = Database::query($sql);
4570
                $affectedRows = Database::affected_rows($result);
4571
            }
4572
        }
4573
4574
        return $affectedRows;
4575
    }
4576
4577
    /**
4578
     * This function check if an user is followed by human resources manager
4579
     * @param     int     $user_id
4580
     * @param    int      $hr_dept_id  Human resources manager
4581
     * @return    bool
4582
     */
4583
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4584
    {
4585
        // Database table and variables Definitions
4586
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4587
        $user_id = intval($user_id);
4588
        $hr_dept_id = intval($hr_dept_id);
4589
        $result = false;
4590
4591
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4592
                WHERE
4593
                    user_id = $user_id AND
4594
                    friend_user_id = $hr_dept_id AND
4595
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4596
        $rs = Database::query($sql);
4597
        if (Database::num_rows($rs) > 0) {
4598
            $result = true;
4599
        }
4600
        return $result;
4601
    }
4602
4603
    /**
4604
     * get user id of teacher or session administrator
4605
     * @param array $courseInfo
4606
     *
4607
     * @return int The user id
4608
     */
4609
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4610
    {
4611
        $session = api_get_session_id();
4612
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4613
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4614
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4615
        $courseId = $courseInfo['real_id'];
4616
4617
        if ($session == 0 || is_null($session)) {
4618
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4619
                    INNER JOIN '.$table_course_user.' ru
4620
                    ON ru.user_id = u.id
4621
                    WHERE
4622
                        ru.status = 1 AND
4623
                        ru.c_id = "'.$courseId.'" ';
4624
            $rs = Database::query($sql);
4625
            $num_rows = Database::num_rows($rs);
4626
            if ($num_rows == 1) {
4627
                $row = Database::fetch_array($rs);
4628
                return $row['uid'];
4629
            } else {
4630
                $my_num_rows = $num_rows;
4631
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4632
4633
                return $my_user_id;
4634
            }
4635
        } elseif ($session > 0) {
4636
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4637
                    INNER JOIN '.$table_session_course_user.' sru
4638
                    ON sru.user_id=u.id
4639
                    WHERE
4640
                        sru.c_id="'.$courseId.'" AND
4641
                        sru.status=2';
4642
            $rs = Database::query($sql);
4643
            $row = Database::fetch_array($rs);
4644
4645
            return $row['uid'];
4646
        }
4647
    }
4648
4649
    /**
4650
     * Determines if a user is a gradebook certified
4651
     * @param int $cat_id The category id of gradebook
4652
     * @param int $user_id The user id
4653
     * @return boolean
4654
     */
4655 View Code Duplication
    public static function is_user_certified($cat_id, $user_id)
4656
    {
4657
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4658
        $sql = 'SELECT path_certificate FROM '.$table_certificate.'
4659
                WHERE
4660
                    cat_id="'.intval($cat_id).'" AND
4661
                    user_id="'.intval($user_id).'"';
4662
        $rs = Database::query($sql);
4663
        $row = Database::fetch_array($rs);
4664
        if ($row['path_certificate'] == '' || is_null($row['path_certificate'])) {
4665
            return false;
4666
        } else {
4667
            return true;
4668
        }
4669
    }
4670
4671
    /**
4672
     * Gets the info about a gradebook certificate for a user by course
4673
     * @param int $courseId course id
4674
     * @param int $user_id The user id
4675
     * @return array  if there is not information return false
4676
     */
4677
    public static function getInfoGradeBookCertificate($courseId, $user_id)
4678
    {
4679
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4680
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4681
        $session_id = api_get_session_id();
4682
4683
        if (empty($session_id)) {
4684
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4685
        } else {
4686
            $session_condition = " AND session_id = $session_id";
4687
        }
4688
4689
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.' 
4690
                WHERE cat_id = (
4691
                    SELECT id FROM '.$tbl_grade_category.'
4692
                    WHERE
4693
                        c_id = "'.Database::escape_string($courseId).'" '.$session_condition.' 
4694
                    LIMIT 1
4695
                 ) 
4696
                 AND user_id='.intval($user_id);
4697
4698
        $rs = Database::query($sql);
4699
        if (Database::num_rows($rs) > 0) {
4700
            $row = Database::fetch_array($rs, 'ASSOC');
4701
            $score = $row['score_certificate'];
4702
            $category_id = $row['cat_id'];
4703
            $cat = Category::load($category_id);
4704
            $displayscore = ScoreDisplay::instance();
4705
            if (isset($cat) && $displayscore->is_custom()) {
4706
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()), SCORE_DIV_PERCENT_WITH_CUSTOM);
4707
            } else {
4708
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()));
4709
            }
4710
            $row['grade'] = $grade;
4711
4712
            return $row;
4713
        }
4714
4715
        return false;
4716
    }
4717
4718
    /**
4719
     * Gets the user path of user certificated
4720
     * @param int The user id
4721
     * @return array  containing path_certificate and cat_id
4722
     */
4723
    public static function get_user_path_certificate($user_id)
4724
    {
4725
        $my_certificate = array();
4726
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4727
        $table_gradebook_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4728
4729
        $session_id = api_get_session_id();
4730
        $user_id = intval($user_id);
4731 View Code Duplication
        if ($session_id == 0 || is_null($session_id)) {
4732
            $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
4733
        } elseif ($session_id > 0) {
4734
            $sql_session = 'AND session_id='.intval($session_id);
4735
        } else {
4736
            $sql_session = '';
4737
        }
4738
        $sql = "SELECT tc.path_certificate,tc.cat_id,tgc.course_code,tgc.name
4739
                FROM $table_certificate tc, $table_gradebook_category tgc
4740
                WHERE tgc.id = tc.cat_id AND tc.user_id = $user_id
4741
                ORDER BY tc.date_certificate DESC 
4742
                LIMIT 5";
4743
4744
        $rs = Database::query($sql);
4745
        while ($row = Database::fetch_array($rs)) {
4746
            $my_certificate[] = $row;
4747
        }
4748
        return $my_certificate;
4749
    }
4750
4751
    /**
4752
     * This function check if the user is a coach inside session course
4753
     * @param  int  $user_id    User id
4754
     * @param  int  $courseId
4755
     * @param  int  $session_id
4756
     * @return bool    True if the user is a coach
4757
     *
4758
     */
4759 View Code Duplication
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4760
    {
4761
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4762
        // Protect data
4763
        $user_id = intval($user_id);
4764
        $courseId = intval($courseId);
4765
        $session_id = intval($session_id);
4766
        $result = false;
4767
4768
        $sql = "SELECT session_id FROM $tbl_session_course_rel_user
4769
                WHERE
4770
                  session_id = $session_id AND
4771
                  c_id = $courseId AND
4772
                  user_id = $user_id AND
4773
                  status = 2 ";
4774
        $res = Database::query($sql);
4775
4776
        if (Database::num_rows($res) > 0) {
4777
            $result = true;
4778
        }
4779
        return $result;
4780
    }
4781
4782
    /**
4783
     * This function returns an icon path that represents the favicon of the website of which the url given.
4784
     * Defaults to the current Chamilo favicon
4785
     * @param    string    $url1 URL of website where to look for favicon.ico
4786
     * @param    string    $url2 Optional second URL of website where to look for favicon.ico
4787
     * @return    string    Path of icon to load
4788
     */
4789
    public static function get_favicon_from_url($url1, $url2 = null)
4790
    {
4791
        $icon_link = '';
4792
        $url = $url1;
4793
        if (empty($url1)) {
4794
            $url = $url2;
4795
            if (empty($url)) {
4796
                $url = api_get_access_url(api_get_current_access_url_id());
4797
                $url = $url[0];
4798
            }
4799
        }
4800
        if (!empty($url)) {
4801
            $pieces = parse_url($url);
4802
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
4803
        }
4804
        return $icon_link;
4805
    }
4806
4807
    /**
4808
     *
4809
     * @param int   student id
4810
     * @param int   years
4811
     * @param bool  show warning_message
4812
     * @param bool  return_timestamp
4813
     */
4814
    public static function delete_inactive_student($student_id, $years = 2, $warning_message = false, $return_timestamp = false)
4815
    {
4816
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
4817
        $sql = 'SELECT login_date FROM '.$tbl_track_login.'
4818
                WHERE login_user_id = '.intval($student_id).'
4819
                ORDER BY login_date DESC LIMIT 0,1';
4820
        if (empty($years)) {
4821
            $years = 1;
4822
        }
4823
        $inactive_time = $years * 31536000; //1 year
4824
        $rs = Database::query($sql);
4825
        if (Database::num_rows($rs) > 0) {
4826
            if ($last_login_date = Database::result($rs, 0, 0)) {
4827
                $last_login_date = api_get_local_time($last_login_date, null, date_default_timezone_get());
4828
                if ($return_timestamp) {
4829
                    return api_strtotime($last_login_date);
4830
                } else {
4831
                    if (!$warning_message) {
4832
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
4833
                    } else {
4834
                        $timestamp = api_strtotime($last_login_date);
4835
                        $currentTimestamp = time();
4836
4837
                        //If the last connection is > than 7 days, the text is red
4838
                        //345600 = 7 days in seconds 63072000= 2 ans
4839
                        // if ($currentTimestamp - $timestamp > 184590 )
4840
                        if ($currentTimestamp - $timestamp > $inactive_time && self::delete_user($student_id)) {
4841
                            echo Display::return_message(get_lang('UserDeleted'));
4842
                            echo '<p>', 'id', $student_id, ':', $last_login_date, '</p>';
4843
                        }
4844
                    }
4845
                }
4846
            }
4847
        }
4848
        return false;
4849
    }
4850
4851
    /**
4852
     * @return array
4853
     */
4854
    public static function get_user_field_types()
4855
    {
4856
        $types = array();
4857
        $types[self::USER_FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
4858
        $types[self::USER_FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
4859
        $types[self::USER_FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
4860
        $types[self::USER_FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
4861
        $types[self::USER_FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
4862
        $types[self::USER_FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
4863
        $types[self::USER_FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
4864
        $types[self::USER_FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
4865
        $types[self::USER_FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
4866
        $types[self::USER_FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
4867
        $types[self::USER_FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
4868
        $types[self::USER_FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
4869
        $types[self::USER_FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
4870
        $types[self::USER_FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
4871
4872
        return $types;
4873
    }
4874
4875
    /**
4876
     * @param User $user
4877
     */
4878
    public static function add_user_as_admin(User $user)
4879
    {
4880
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
4881
        if ($user) {
4882
            $userId = $user->getId();
4883
4884
            if (!self::is_admin($userId)) {
4885
                $sql = "INSERT INTO $table_admin SET user_id = $userId";
4886
                Database::query($sql);
4887
            }
4888
4889
            $user->addRole('ROLE_SUPER_ADMIN');
4890
            self::getManager()->updateUser($user, true);
4891
        }
4892
    }
4893
4894
    /**
4895
     * @param int $userId
4896
     */
4897 View Code Duplication
    public static function remove_user_admin($userId)
4898
    {
4899
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
4900
        $userId = intval($userId);
4901
        if (self::is_admin($userId)) {
4902
            $sql = "DELETE FROM $table_admin WHERE user_id = $userId";
4903
            Database::query($sql);
4904
        }
4905
    }
4906
4907
    /**
4908
     * @param string $from
4909
     * @param string $to
4910
     */
4911
    public static function update_all_user_languages($from, $to)
4912
    {
4913
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4914
        $from = Database::escape_string($from);
4915
        $to = Database::escape_string($to);
4916
4917
        if (!empty($to) && !empty($from)) {
4918
            $sql = "UPDATE $table_user SET language = '$to'
4919
                    WHERE language = '$from'";
4920
            Database::query($sql);
4921
        }
4922
    }
4923
4924
    /**
4925
     * Subscribe boss to students
4926
     *
4927
     * @param int $bossId The boss id
4928
     * @param array $usersId The users array
4929
     * @return int Affected rows
4930
     */
4931
    public static function subscribeBossToUsers($bossId, $usersId)
4932
    {
4933
        return self::subscribeUsersToUser($bossId, $usersId, USER_RELATION_TYPE_BOSS);
4934
    }
4935
4936
    /**
4937
     * Subscribe boss to students
4938
     *
4939
     * @param int $studentId
4940
     * @param array $bossList
4941
     * @return int Affected rows
4942
     */
4943
    public static function subscribeUserToBossList($studentId, $bossList)
4944
    {
4945
        if ($bossList) {
4946
            $studentId = (int) $studentId;
4947
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4948
            $sql = "DELETE FROM $userRelUserTable 
4949
                    WHERE user_id = $studentId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4950
            Database::query($sql);
4951
4952
            foreach ($bossList as $bossId) {
4953
                $bossId = (int) $bossId;
4954
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4955
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
4956
4957
                Database::query($sql);
4958
            }
4959
        }
4960
    }
4961
4962
    /**
4963
     * Get users followed by student boss
4964
     * @param int $userId
4965
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
4966
     * @param bool $getOnlyUserId
4967
     * @param bool $getSql
4968
     * @param bool $getCount
4969
     * @param int $from
4970
     * @param int $numberItems
4971
     * @param int $column
4972
     * @param string $direction
4973
     * @param int $active
4974
     * @param string $lastConnectionDate
4975
     * @return array     users
4976
     */
4977 View Code Duplication
    public static function getUsersFollowedByStudentBoss(
4978
        $userId,
4979
        $userStatus = 0,
4980
        $getOnlyUserId = false,
4981
        $getSql = false,
4982
        $getCount = false,
4983
        $from = null,
4984
        $numberItems = null,
4985
        $column = null,
4986
        $direction = null,
4987
        $active = null,
4988
        $lastConnectionDate = null
4989
    ) {
4990
        return self::getUsersFollowedByUser(
4991
            $userId,
4992
            $userStatus,
4993
            $getOnlyUserId,
4994
            $getSql,
4995
            $getCount,
4996
            $from,
4997
            $numberItems,
4998
            $column,
4999
            $direction,
5000
            $active,
5001
            $lastConnectionDate,
5002
            STUDENT_BOSS
5003
        );
5004
    }
5005
5006
    /**
5007
     * Get the teacher (users with COURSEMANGER status) list
5008
     * @return array The list
5009
     */
5010
    public static function getTeachersList()
5011
    {
5012
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5013
5014
        $resultData = Database::select('user_id, lastname, firstname, username', $userTable, array(
5015
            'where' => array(
5016
                'status = ?' => COURSEMANAGER
5017
            )
5018
        ));
5019
5020
        foreach ($resultData as &$teacherData) {
5021
            $teacherData['completeName'] = api_get_person_name($teacherData['firstname'], $teacherData['lastname']);
5022
        }
5023
5024
        return $resultData;
5025
    }
5026
5027
    /**
5028
     * @return array
5029
     */
5030 View Code Duplication
    public static function getOfficialCodeGrouped()
5031
    {
5032
        $user = Database::get_main_table(TABLE_MAIN_USER);
5033
        $sql = "SELECT DISTINCT official_code
5034
                FROM $user
5035
                GROUP BY official_code";
5036
        $result = Database::query($sql);
5037
5038
        $values = Database::store_result($result, 'ASSOC');
5039
5040
        $result = array();
5041
        foreach ($values as $value) {
5042
            $result[$value['official_code']] = $value['official_code'];
5043
        }
5044
        return $result;
5045
    }
5046
5047
    /**
5048
     * @param string $officialCode
5049
     * @return array
5050
     */
5051
    public static function getUsersByOfficialCode($officialCode)
5052
    {
5053
        $user = Database::get_main_table(TABLE_MAIN_USER);
5054
        $officialCode = Database::escape_string($officialCode);
5055
5056
        $sql = "SELECT DISTINCT id
5057
                FROM $user
5058
                WHERE official_code = '$officialCode'
5059
                ";
5060
        $result = Database::query($sql);
5061
5062
        $users = array();
5063
        while ($row = Database::fetch_array($result)) {
5064
            $users[] = $row['id'];
5065
        }
5066
        return $users;
5067
    }
5068
5069
    /**
5070
     * Calc the expended time (in seconds) by a user in a course
5071
     * @param int $userId The user id
5072
     * @param int $courseId The course id
5073
     * @param int $sessionId Optional. The session id
5074
     * @param string $from Optional. From date
5075
     * @param string $until Optional. Until date
5076
     * @return int The time
5077
     */
5078
    public static function getTimeSpentInCourses($userId, $courseId, $sessionId = 0, $from = '', $until = '')
5079
    {
5080
        $userId = intval($userId);
5081
        $sessionId = intval($sessionId);
5082
5083
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5084
5085
        $whereConditions = array(
5086
            'user_id = ? ' => $userId,
5087
            'AND c_id = ? ' => $courseId,
5088
            'AND session_id = ? ' => $sessionId
5089
        );
5090
5091 View Code Duplication
        if (!empty($from) && !empty($until)) {
5092
            $whereConditions["AND (login_course_date >= '?' "] = $from;
5093
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
5094
        }
5095
5096
        $trackResult = Database::select(
5097
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
5098
            $trackCourseAccessTable,
5099
            array(
5100
                'where' => $whereConditions
5101
            ), 'first'
5102
        );
5103
5104
        if ($trackResult != false) {
5105
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5106
        }
5107
5108
        return 0;
5109
    }
5110
5111
    /**
5112
     * Get the boss user ID from a followed user id
5113
     * @param $userId
5114
     * @return bool
5115
     */
5116 View Code Duplication
    public static function getFirstStudentBoss($userId)
5117
    {
5118
        $userId = intval($userId);
5119
        if ($userId > 0) {
5120
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5121
            $row = Database::select(
5122
                'DISTINCT friend_user_id AS boss_id',
5123
                $userRelTable,
5124
                array(
5125
                    'where' => array(
5126
                        'user_id = ? AND relation_type = ? LIMIT 1' => array(
5127
                            $userId,
5128
                            USER_RELATION_TYPE_BOSS,
5129
                        )
5130
                    )
5131
                )
5132
            );
5133
            if (!empty($row)) {
5134
5135
                return $row[0]['boss_id'];
5136
            }
5137
        }
5138
5139
        return false;
5140
    }
5141
5142
    /**
5143
     * Get the boss user ID from a followed user id
5144
     * @param $userId
5145
     * @return bool
5146
     */
5147 View Code Duplication
    public static function getStudentBossList($userId)
5148
    {
5149
        $userId = intval($userId);
5150
        if ($userId > 0) {
5151
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5152
            $result = Database::select(
5153
                'DISTINCT friend_user_id AS boss_id',
5154
                $userRelTable,
5155
                array(
5156
                    'where' => array(
5157
                        'user_id = ? AND relation_type = ? ' => array(
5158
                            $userId,
5159
                            USER_RELATION_TYPE_BOSS,
5160
                        )
5161
                    )
5162
                ),
5163
                'all'
5164
            );
5165
5166
            return $result;
5167
        }
5168
5169
        return false;
5170
    }
5171
5172
    /**
5173
     * @param int $bossId
5174
     * @param int $studentId
5175
     *
5176
     * @return bool
5177
     */
5178
    public static function userIsBossOfStudent($bossId, $studentId)
5179
    {
5180
        $result = false;
5181
        $bossList = self::getStudentBossList($studentId);
5182
        if ($bossList) {
5183
            $bossList = array_column($bossList, 'boss_id');
5184
            if (in_array($bossId, $bossList)) {
5185
                $result = true;
5186
            }
5187
        }
5188
5189
        return $result;
5190
    }
5191
5192
    /**
5193
     * Get either a Gravatar URL or complete image tag for a specified email address.
5194
     *
5195
     * @param string $email The email address
5196
     * @param string $s Size in pixels, defaults to 80px [ 1 - 2048 ]
5197
     * @param string $d Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
5198
     * @param string $r Maximum rating (inclusive) [ g | pg | r | x ]
5199
     * @param boole $img True to return a complete IMG tag False for just the URL
5200
     * @param array $atts Optional, additional key/value attributes to include in the IMG tag
5201
     * @return String containing either just a URL or a complete image tag
5202
     * @source http://gravatar.com/site/implement/images/php/
5203
     */
5204
    private static function getGravatar(
5205
        $email,
5206
        $s = 80,
5207
        $d = 'mm',
5208
        $r = 'g',
5209
        $img = false,
5210
        $atts = array()
5211
    ) {
5212
        $url = 'http://www.gravatar.com/avatar/';
5213
        if (!empty($_SERVER['HTTPS'])) {
5214
            $url = 'https://secure.gravatar.com/avatar/';
5215
        }
5216
        $url .= md5(strtolower(trim($email)));
5217
        $url .= "?s=$s&d=$d&r=$r";
5218
        if ($img) {
5219
            $url = '<img src="'.$url.'"';
5220
            foreach ($atts as $key => $val)
5221
                $url .= ' '.$key.'="'.$val.'"';
5222
            $url .= ' />';
5223
        }
5224
        return $url;
5225
    }
5226
5227
    /**
5228
     * Displays the name of the user and makes the link to the user profile
5229
     * @param array $userInfo
5230
     *
5231
     * @return string
5232
     */
5233
    public static function getUserProfileLink($userInfo)
5234
    {
5235
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5236
            return Display::url(
5237
                $userInfo['complete_name_with_username'],
5238
                $userInfo['profile_url']
5239
            );
5240
        } else {
5241
            return get_lang('Anonymous');
5242
        }
5243
    }
5244
5245
    /**
5246
     * Displays the name of the user and makes the link to the user profile
5247
     *
5248
     * @param $userInfo
5249
     *
5250
     * @return string
5251
     */
5252
    public static function getUserProfileLinkWithPicture($userInfo)
5253
    {
5254
        return Display::url(Display::img($userInfo['avatar']), $userInfo['profile_url']);
5255
    }
5256
5257
    /**
5258
     * Get users whose name matches $firstname and $lastname
5259
     * @param string $firstname Firstname to search
5260
     * @param string $lastname Lastname to search
5261
     * @return array The user list
5262
     */
5263 View Code Duplication
    public static function getUserByName($firstname, $lastname)
5264
    {
5265
        $firstname = Database::escape_string($firstname);
5266
        $lastname = Database::escape_string($lastname);
5267
5268
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5269
5270
        $sql = <<<SQL
5271
            SELECT id, username, lastname, firstname
5272
            FROM $userTable
5273
            WHERE 
5274
                firstname LIKE '$firstname%' AND
5275
                lastname LIKE '$lastname%'
5276
SQL;
5277
5278
        $result = Database::query($sql);
5279
5280
        $users = [];
5281
        while ($resultData = Database::fetch_object($result)) {
5282
            $users[] = $resultData;
5283
        }
5284
5285
        return $users;
5286
    }
5287
5288
    /**
5289
     * @param int $optionSelected
5290
     * @return string
5291
     */
5292
    public static function getUserSubscriptionTab($optionSelected = 1)
5293
    {
5294
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5295
        if (($allowAdmin === 'true' && api_is_allowed_to_edit()) ||
5296
            api_is_platform_admin()
5297
        ) {
5298
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5299
5300
            $headers = [
5301
                [
5302
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5303
                    'content' => get_lang('Students'),
5304
                ],
5305
                [
5306
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5307
                    'content' => get_lang('Teachers'),
5308
                ],
5309
                /*[
5310
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5311
                    'content' => get_lang('Students'),
5312
                ],
5313
                [
5314
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5315
                    'content' => get_lang('Teachers'),
5316
                ],*/
5317
                [
5318
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5319
                    'content' => get_lang('Groups'),
5320
                ],
5321
                [
5322
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5323
                    'content' => get_lang('Classes'),
5324
                ]
5325
            ];
5326
5327
            return Display::tabsOnlyLink($headers, $optionSelected);
5328
        }
5329
    }
5330
5331
5332
    /**
5333
     * @param int $user_id
5334
     * @return bool
5335
     */
5336 View Code Duplication
    public static function user_is_online($user_id)
5337
    {
5338
        $track_online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5339
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5340
5341
        $access_url_id = api_get_current_access_url_id();
5342
        $time_limit = api_get_setting('display.time_limit_whosonline');
5343
5344
        $online_time = time() - $time_limit*60;
5345
        $limit_date = api_get_utc_datetime($online_time);
5346
        $user_id = intval($user_id);
5347
5348
        $query = " SELECT login_user_id,login_date
5349
               FROM $track_online_table track
5350
               INNER JOIN $table_user u ON (u.id=track.login_user_id)
5351
               WHERE
5352
                    track.access_url_id =  $access_url_id AND
5353
                    login_date >= '".$limit_date."'  AND
5354
                    u.id =  $user_id
5355
               LIMIT 1 ";
5356
5357
        $result = Database::query($query);
5358
        if (Database::num_rows($result)) {
5359
5360
            return true;
5361
        }
5362
5363
        return false;
5364
    }
5365
5366
    /**
5367
     * @param int $time_limit seconds
5368
     * @param bool $friends show friends (true) or all users (false)
5369
     * @return bool
5370
     */
5371
    public static function whoIsOnlineCount(
5372
        $time_limit = 0,
5373
        $friends = false
5374
    ) {
5375
        if (empty($time_limit)) {
5376
            $time_limit = api_get_setting('display.time_limit_whosonline');
5377
        } else {
5378
            $time_limit = intval($time_limit);
5379
        }
5380
        $track_online_table = Database::get_main_table(
5381
            TABLE_STATISTIC_TRACK_E_ONLINE
5382
        );
5383
        $friend_user_table = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5384
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5385
        $online_time = time() - $time_limit * 60;
5386
        $current_date = api_get_utc_datetime($online_time);
5387
5388
        if ($friends) {
5389
            // 	who friends from social network is online
5390
            $query = "SELECT DISTINCT count(login_user_id) as count
5391
				  FROM $track_online_table INNER JOIN $friend_user_table
5392
                  ON (friend_user_id = login_user_id)
5393
				  WHERE
5394
				        login_date >= '$current_date' AND
5395
				        friend_user_id <> '".api_get_user_id()."' AND
5396
				        relation_type='".USER_RELATION_TYPE_FRIEND."' AND
5397
				        user_id = '".api_get_user_id()."' ";
5398
        } else {
5399
            // All users online
5400
            $query = "SELECT count(login_id) as count
5401
                  FROM $track_online_table track INNER JOIN $table_user u
5402
                  ON (u.id=track.login_user_id)
5403
                  WHERE u.status != ".ANONYMOUS." AND login_date >= '$current_date'  ";
5404
        }
5405
5406
        if (api_get_multiple_access_url()) {
5407
            $access_url_id = api_get_current_access_url_id();
5408
            if ($access_url_id != -1) {
5409
                if ($friends) {
5410
                    // 	friends from social network is online
5411
                    $query = "SELECT DISTINCT count(login_user_id) as count
5412
							FROM $track_online_table track
5413
							INNER JOIN $friend_user_table ON (friend_user_id = login_user_id)
5414
							WHERE
5415
							    track.access_url_id = $access_url_id AND
5416
							    login_date >= '".$current_date."' AND
5417
							    friend_user_id <> '".api_get_user_id()."' AND
5418
							    relation_type='".USER_RELATION_TYPE_FRIEND."'  ";
5419
                } else {
5420
                    // all users online
5421
                    $query = "SELECT count(login_id) as count FROM $track_online_table  track
5422
                          INNER JOIN $table_user u ON (u.id=track.login_user_id)
5423
						  WHERE
5424
						    u.status != ".ANONYMOUS." AND
5425
						    track.access_url_id =  $access_url_id AND
5426
						    login_date >= '$current_date' ";
5427
                }
5428
            }
5429
        }
5430
5431
        // Dev purposes show all users online
5432
        /*$table_user = Database::get_main_table(TABLE_MAIN_USER);
5433
        $query = "SELECT count(*)  as count FROM ".$table_user;*/
5434
5435
        $result = Database::query($query);
5436
        if (Database::num_rows($result) > 0) {
5437
            $row = Database::fetch_array($result);
5438
5439
            return $row['count'];
5440
        } else {
5441
            return false;
5442
        }
5443
    }
5444
5445
    /**
5446
     * Gives a list of people online now (and in the last $valid minutes)
5447
     *
5448
     * @param int $from
5449
     * @param int $number_of_items
5450
     * @param string $column
5451
     * @param string $direction
5452
     * @param int $time_limit in seconds
5453
     * @param bool $friends show friends (true) or all users (false)
5454
     * @return array|bool
5455
     */
5456
    public static function whoIsOnline(
5457
        $from,
5458
        $number_of_items,
5459
        $column = '',
5460
        $direction = '',
5461
        $time_limit = 0,
5462
        $friends = false
5463
    ) {
5464
        // Time limit in seconds?
5465
        if (empty($time_limit)) {
5466
            $time_limit = api_get_setting('display.time_limit_whosonline');
5467
        } else {
5468
            $time_limit = intval($time_limit);
5469
        }
5470
5471
        $from = intval($from);
5472
        $number_of_items = intval($number_of_items);
5473
5474
        if (empty($column)) {
5475
            $column = 'picture_uri';
5476
            if ($friends) {
5477
                $column = 'login_date';
5478
            }
5479
        }
5480
5481
        if (empty($direction)) {
5482
            $direction = 'DESC';
5483
        } else {
5484
            if (!in_array(strtolower($direction), array('asc', 'desc'))) {
5485
                $direction = 'DESC';
5486
            }
5487
        }
5488
5489
        $online_time = time() - $time_limit * 60;
5490
        $current_date = api_get_utc_datetime($online_time);
5491
        $track_online_table = Database::get_main_table(
5492
            TABLE_STATISTIC_TRACK_E_ONLINE
5493
        );
5494
        $friend_user_table = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5495
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5496
5497
        if ($friends) {
5498
            // 	who friends from social network is online
5499
            $query = "SELECT DISTINCT login_user_id, login_date
5500
				  FROM $track_online_table INNER JOIN $friend_user_table
5501
				  ON (friend_user_id = login_user_id)
5502
				  WHERE
5503
				    login_date >= '".$current_date."' AND
5504
                    friend_user_id <> '".api_get_user_id()."' AND
5505
                    relation_type='".USER_RELATION_TYPE_FRIEND."' AND
5506
                    user_id = '".api_get_user_id()."'
5507
                  ORDER BY $column $direction
5508
                  LIMIT $from, $number_of_items";
5509
        } else {
5510
            $query = "SELECT DISTINCT login_user_id, login_date
5511
                    FROM ".$track_online_table." e
5512
		            INNER JOIN ".$table_user." u ON (u.id = e.login_user_id)
5513
                  WHERE u.status != ".ANONYMOUS." AND login_date >= '".$current_date."'
5514
                  ORDER BY $column $direction
5515
                  LIMIT $from, $number_of_items";
5516
        }
5517
5518
        if (api_get_multiple_access_url()) {
5519
            $access_url_id = api_get_current_access_url_id();
5520
            if ($access_url_id != -1) {
5521
                if ($friends) {
5522
                    // 	friends from social network is online
5523
                    $query = "SELECT distinct login_user_id, login_date
5524
							FROM $track_online_table track INNER JOIN $friend_user_table
5525
							ON (friend_user_id = login_user_id)
5526
							WHERE   track.access_url_id =  $access_url_id AND
5527
                                    login_date >= '".$current_date."' AND
5528
                                    friend_user_id <> '".api_get_user_id()."' AND
5529
                                    relation_type='".USER_RELATION_TYPE_FRIEND."'
5530
                            ORDER BY $column $direction
5531
                            LIMIT $from, $number_of_items";
5532
                } else {
5533
                    // all users online
5534
                    $query = "SELECT login_user_id, login_date
5535
						  FROM ".$track_online_table." track
5536
                          INNER JOIN ".$table_user." u
5537
                          ON (u.id=track.login_user_id)
5538
						  WHERE u.status != ".ANONYMOUS." AND track.access_url_id =  $access_url_id AND
5539
                                login_date >= '".$current_date."'
5540
                          ORDER BY $column $direction
5541
                          LIMIT $from, $number_of_items";
5542
                }
5543
            }
5544
        }
5545
5546
        //This query will show all registered users. Only for dev purposes.
5547
        /*$query = "SELECT DISTINCT u.id as login_user_id, login_date FROM ".$track_online_table ."  e , $table_user u
5548
                GROUP by u.id
5549
                ORDER BY $column $direction
5550
                LIMIT $from, $number_of_items";*/
5551
5552
        $result = Database::query($query);
5553
        if ($result) {
5554
            $users_online = array();
5555
            while (list($login_user_id, $login_date) = Database::fetch_row($result)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $login_date is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
5556
                $users_online[] = $login_user_id;
5557
            }
5558
5559
            return $users_online;
5560
        } else {
5561
            return false;
5562
        }
5563
    }
5564
5565
    /**
5566
     * @param int $user_id
5567
     * @param bool $is_time_over
5568
     * @param bool $get_count
5569
     * @param bool $reverse_order
5570
     * @param int $start
5571
     * @param null $maxPerPage
5572
     * @param null $categoryFilter
5573
     * @return array
5574
     */
5575
    public static function getCategories(
5576
        $user_id,
5577
        $is_time_over = false,
5578
        $get_count = false,
5579
        $reverse_order = false,
5580
        $start = 0,
5581
        $maxPerPage = null,
5582
        $categoryFilter = null
5583
    ) {
5584
        $tableSessionCategory = Database:: get_main_table(
5585
            TABLE_MAIN_SESSION_CATEGORY
5586
        );
5587
        $tableSession = Database:: get_main_table(TABLE_MAIN_SESSION);
5588
        $tableSessionUser = Database:: get_main_table(TABLE_MAIN_SESSION_USER);
5589
        $tableSessionCourseUser = Database:: get_main_table(
5590
            TABLE_MAIN_SESSION_COURSE_USER
5591
        );
5592
5593
        $select = " DISTINCT sc.id, sc.name  ";
5594
        if ($get_count) {
5595
            $select = " COUNT(DISTINCT(sc.id)) as total";
5596
        }
5597
5598
        $sql = "SELECT $select
5599
                FROM $tableSessionCategory sc
5600
                INNER JOIN $tableSession s ON (sc.id = s.session_category_id)
5601
                INNER JOIN (
5602
                    (
5603
                        SELECT DISTINCT session_id as sessionID FROM $tableSessionUser
5604
                        WHERE user_id = $user_id AND relation_type <> ".SESSION_RELATION_TYPE_RRHH."
5605
                    )
5606
                    UNION
5607
                    (
5608
                        SELECT DISTINCT s.id
5609
                        FROM $tableSession s
5610
                        WHERE (id_coach = $user_id)
5611
                    )
5612
                    UNION
5613
                    (
5614
                        SELECT DISTINCT s.id
5615
                        FROM $tableSessionUser su INNER JOIN $tableSession s
5616
                        ON (su.session_id = s.id)
5617
                        INNER JOIN $tableSessionCourseUser scu
5618
                        ON (scu.session_id = s.id)
5619
                        WHERE (scu.user_id = $user_id)
5620
                    )
5621
                ) as t ON (t.sessionId = sc.id)
5622
        ";
5623
5624
        if ($get_count) {
5625
            $result = Database::query($sql);
5626
            $row = Database::fetch_array($result);
5627
5628
            return $row['total'];
5629
        }
5630
5631
        $order = ' ORDER BY sc.name';
5632
        if ($reverse_order) {
5633
            $order = ' ORDER BY sc.name DESC ';
5634
        }
5635
5636
        $sql .= $order;
5637
5638 View Code Duplication
        if (isset($start) && isset($maxPerPage)) {
5639
            $start = intval($start);
5640
            $maxPerPage = intval($maxPerPage);
5641
            $limitCondition = " LIMIT $start, $maxPerPage";
5642
            $sql .= $limitCondition;
5643
        }
5644
5645
        $result = Database::query($sql);
5646
        $sessionsCategories = array();
5647
        if (Database::num_rows($result)) {
5648
            while ($sessionCategory = Database::fetch_array($result, 'ASSOC')) {
5649
                $sessions = self::get_sessions_by_category(
5650
                    $user_id,
5651
                    $is_time_over,
5652
                    false,
5653
                    $reverse_order,
5654
                    null,
5655
                    null,
5656
                    $sessionCategory['id']
5657
                );
5658
                $sessionsCategories[$sessionCategory['id']] = $sessions[$sessionCategory['id']];
5659
            }
5660
        }
5661
5662
        return $sessionsCategories;
5663
    }
5664
5665
5666
}
5667