Test Setup Failed
Push — master ( 4e700f...c7183e )
by Julito
63:12
created

UserManager::get_user_upload_files_by_course()   C

Complexity

Conditions 16
Paths 6

Size

Total Lines 45
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 29
nc 6
nop 3
dl 0
loc 45
rs 5.0151
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
            return array();
1418
        }
1419
1420
        $ids = is_array($ids) ? $ids : array($ids);
1421
        $ids = array_map('intval', $ids);
1422
        $ids = implode(',', $ids);
1423
1424
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1425
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1426
        if (!is_null($active)) {
1427
            $sql .= ' AND active='.($active ? '1' : '0');
1428
        }
1429
1430
        if (!is_null($order)) {
1431
            $order = Database::escape_string($order);
1432
            $sql .= ' ORDER BY '.$order;
1433
        }
1434
1435
        if (!is_null($limit)) {
1436
            $limit = Database::escape_string($limit);
1437
            $sql .= ' LIMIT '.$limit;
1438
        }
1439
1440
        $rs = Database::query($sql);
1441
        $result = array();
1442
        while ($row = Database::fetch_array($rs)) {
1443
            $result[] = $row;
1444
        }
1445
1446
        return $result;
1447
    }
1448
1449
    /**
1450
     * Get a list of users of which the given conditions match with an = 'cond'
1451
     * @param array $conditions a list of condition (example : status=>STUDENT)
1452
     * @param array $order_by a list of fields on which sort
1453
     * @return array An array with all users of the platform.
1454
     * @todo optional course code parameter, optional sorting parameters...
1455
     * @todo security filter order by
1456
     */
1457
    public static function get_user_list(
1458
        $conditions = [],
1459
        $order_by = [],
1460
        $limit_from = false,
1461
        $limit_to = false
1462
    ) {
1463
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1464
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1465
        $urlId = api_get_current_access_url_id();
1466
1467
        $return_array = array();
1468
        $sql = "SELECT user.* FROM $user_table user
1469
                INNER JOIN $userUrlTable url_user
1470
                ON (user.user_id = url_user.user_id)
1471
                WHERE url_user.access_url_id = $urlId
1472
        ";
1473
1474
        if (count($conditions) > 0) {
1475
            foreach ($conditions as $field => $value) {
1476
                $field = Database::escape_string($field);
1477
                $value = Database::escape_string($value);
1478
                $sql .= " AND $field = '$value'";
1479
            }
1480
        }
1481
1482 View Code Duplication
        if (count($order_by) > 0) {
1483
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1484
        }
1485
1486
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1487
            $limit_from = intval($limit_from);
1488
            $limit_to = intval($limit_to);
1489
            $sql .= " LIMIT $limit_from, $limit_to";
1490
        }
1491
        $sql_result = Database::query($sql);
1492 View Code Duplication
        while ($result = Database::fetch_array($sql_result)) {
1493
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1494
            $return_array[] = $result;
1495
        }
1496
        return $return_array;
1497
    }
1498
1499
    /**
1500
     * Get a list of users of which the given conditions match with a LIKE '%cond%'
1501
     * @param array $conditions a list of condition (exemple : status=>STUDENT)
1502
     * @param array $order_by a list of fields on which sort
1503
     * @return array An array with all users of the platform.
1504
     * @todo optional course code parameter, optional sorting parameters...
1505
     * @todo security filter order_by
1506
     */
1507
    public static function get_user_list_like(
1508
        $conditions = array(),
1509
        $order_by = array(),
1510
        $simple_like = false,
1511
        $condition = 'AND'
1512
    ) {
1513
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1514
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1515
        $return_array = array();
1516
        $sql_query = "SELECT user.id FROM $user_table user ";
1517
1518
        if (api_is_multiple_url_enabled()) {
1519
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
1520
        }
1521
1522
        if (count($conditions) > 0) {
1523
            $sql_query .= ' WHERE ';
1524
            $temp_conditions = array();
1525
            foreach ($conditions as $field => $value) {
1526
                $field = Database::escape_string($field);
1527
                $value = Database::escape_string($value);
1528 View Code Duplication
                if ($simple_like) {
1529
                    $temp_conditions[] = $field." LIKE '$value%'";
1530
                } else {
1531
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1532
                }
1533
            }
1534
            if (!empty($temp_conditions)) {
1535
                $sql_query .= implode(' '.$condition.' ', $temp_conditions);
1536
            }
1537
1538
            if (api_is_multiple_url_enabled()) {
1539
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1540
            }
1541
        } else {
1542
            if (api_is_multiple_url_enabled()) {
1543
                $sql_query .= ' WHERE auru.access_url_id = '.api_get_current_access_url_id();
1544
            }
1545
        }
1546 View Code Duplication
        if (count($order_by) > 0) {
1547
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1548
        }
1549
1550
        $sql_result = Database::query($sql_query);
1551
        while ($result = Database::fetch_array($sql_result)) {
1552
            $userInfo = api_get_user_info($result['id']);
1553
            $return_array[] = $userInfo;
1554
        }
1555
1556
        return $return_array;
1557
    }
1558
1559
    /**
1560
     * Get user picture URL or path from user ID (returns an array).
1561
     * The return format is a complete path, enabling recovery of the directory
1562
     * with dirname() or the file with basename(). This also works for the
1563
     * functions dealing with the user's productions, as they are located in
1564
     * the same directory.
1565
     * @param   integer   $id User ID
1566
     * @param   string    $type Type of path to return (can be 'system', 'web')
1567
     * @param   array $userInfo user information to avoid query the DB
1568
     * returns the /main/img/unknown.jpg image set it at true
1569
     *
1570
     * @return    array     Array of 2 elements: 'dir' and 'file' which contain
1571
     * the dir and file as the name implies if image does not exist it will
1572
     * return the unknow image if anonymous parameter is true if not it returns an empty array
1573
     */
1574 View Code Duplication
    public static function get_user_picture_path_by_id($id, $type = 'web', $userInfo = [])
1575
    {
1576
        switch ($type) {
1577
            case 'system': // Base: absolute system path.
1578
                $base = api_get_path(SYS_CODE_PATH);
1579
                break;
1580
            case 'web': // Base: absolute web path.
1581
            default:
1582
                $base = api_get_path(WEB_CODE_PATH);
1583
                break;
1584
        }
1585
1586
        $anonymousPath = array(
1587
            'dir' => $base.'img/',
1588
            'file' => 'unknown.jpg',
1589
            'email' => ''
1590
        );
1591
1592
        if (empty($id) || empty($type)) {
1593
            return $anonymousPath;
1594
        }
1595
1596
        $id = intval($id);
1597
        if (empty($userInfo)) {
1598
            $user_table = Database::get_main_table(TABLE_MAIN_USER);
1599
            $sql = "SELECT email, picture_uri FROM $user_table
1600
                    WHERE id=".$id;
1601
            $res = Database::query($sql);
1602
1603
            if (!Database::num_rows($res)) {
1604
                return $anonymousPath;
1605
            }
1606
            $user = Database::fetch_array($res);
1607
            if (empty($user['picture_uri'])) {
1608
                return $anonymousPath;
1609
            }
1610
        } else {
1611
            $user = $userInfo;
1612
        }
1613
1614
        $pictureFilename = trim($user['picture_uri']);
1615
1616
        $dir = self::getUserPathById($id, $type);
1617
1618
        return array(
1619
            'dir' => $dir,
1620
            'file' => $pictureFilename,
1621
            'email' => $user['email']
1622
        );
1623
    }
1624
1625
    /**
1626
     * *** READ BEFORE REVIEW THIS FUNCTION ***
1627
     * This function is a exact copy from get_user_picture_path_by_id() and it was create it to avoid
1628
     * a recursive calls for get_user_picture_path_by_id() in another functions when you update a user picture
1629
     * in same script, so you can find this function usage in update_user_picture() function.
1630
     *
1631
     * @param   integer   $id User ID
1632
     * @param   string    $type Type of path to return (can be 'system', 'web')
1633
     * @param   array $userInfo user information to avoid query the DB
1634
     * returns the /main/img/unknown.jpg image set it at true
1635
     *
1636
     * @return    array     Array of 2 elements: 'dir' and 'file' which contain
1637
     * the dir and file as the name implies if image does not exist it will
1638
     * return the unknown image if anonymous parameter is true if not it returns an empty array
1639
     */
1640 View Code Duplication
    public static function getUserPicturePathById($id, $type = 'web', $userInfo = [])
1641
    {
1642
        switch ($type) {
1643
            case 'system': // Base: absolute system path.
1644
                $base = api_get_path(SYS_CODE_PATH);
1645
                break;
1646
            case 'web': // Base: absolute web path.
1647
            default:
1648
                $base = api_get_path(WEB_CODE_PATH);
1649
                break;
1650
        }
1651
1652
        $anonymousPath = array(
1653
            'dir' => $base.'img/',
1654
            'file' => 'unknown.jpg',
1655
            'email' => ''
1656
        );
1657
1658
        if (empty($id) || empty($type)) {
1659
            return $anonymousPath;
1660
        }
1661
1662
        $id = intval($id);
1663
1664
        if (empty($userInfo)) {
1665
            $user_table = Database::get_main_table(TABLE_MAIN_USER);
1666
            $sql = "SELECT email, picture_uri FROM $user_table WHERE id=$id";
1667
            $res = Database::query($sql);
1668
1669
            if (!Database::num_rows($res)) {
1670
                return $anonymousPath;
1671
            }
1672
            $user = Database::fetch_array($res);
1673
1674
            if (empty($user['picture_uri'])) {
1675
                return $anonymousPath;
1676
            }
1677
        } else {
1678
            $user = $userInfo;
1679
        }
1680
1681
        $pictureFilename = trim($user['picture_uri']);
1682
1683
        $dir = self::getUserPathById($id, $type);
1684
1685
        return array(
1686
            'dir' => $dir,
1687
            'file' => $pictureFilename,
1688
            'email' => $user['email']
1689
        );
1690
    }
1691
1692
    /**
1693
     * Get user path from user ID (returns an array).
1694
     * The return format is a complete path to a folder ending with "/"
1695
     * In case the first level of subdirectory of users/ does not exist, the
1696
     * function will attempt to create it. Probably not the right place to do it
1697
     * but at least it avoids headaches in many other places.
1698
     * @param   integer $id User ID
1699
     * @param   string  $type Type of path to return (can be 'system', 'web', 'last')
1700
     * @return  string  User folder path (i.e. /var/www/chamilo/app/upload/users/1/1/)
1701
     */
1702
    public static function getUserPathById($id, $type)
1703
    {
1704
        $id = intval($id);
1705
        if (!$id) {
1706
            return null;
1707
        }
1708
1709
        $userPath = "users/$id/";
1710
        if (api_get_setting('split_users_upload_directory') === 'true') {
1711
            $userPath = 'users/'.substr((string) $id, 0, 1).'/'.$id.'/';
1712
            // In exceptional cases, on some portals, the intermediate base user
1713
            // directory might not have been created. Make sure it is before
1714
            // going further.
1715
1716
            $rootPath = api_get_path(SYS_UPLOAD_PATH).'users/'.substr((string) $id, 0, 1);
1717
            if (!is_dir($rootPath)) {
1718
                $perm = api_get_permissions_for_new_directories();
1719
                try {
1720
                    mkdir($rootPath, $perm);
1721
                } catch (Exception $e) {
1722
                    error_log($e->getMessage());
1723
                }
1724
            }
1725
        }
1726
        switch ($type) {
1727
            case 'system': // Base: absolute system path.
1728
                $userPath = api_get_path(SYS_UPLOAD_PATH).$userPath;
1729
                break;
1730
            case 'web': // Base: absolute web path.
1731
                $userPath = api_get_path(WEB_UPLOAD_PATH).$userPath;
1732
                break;
1733
            case 'last': // Only the last part starting with users/
1734
                break;
1735
        }
1736
1737
        return $userPath;
1738
    }
1739
1740
    /**
1741
     * Gets the current user image
1742
     * @param string $user_id
1743
     * @param int $size it can be USER_IMAGE_SIZE_SMALL,
1744
     * USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1745
     * @param bool $addRandomId
1746
     * @param array $userInfo to avoid query the DB
1747
     *
1748
     * @return string
1749
     */
1750
    public static function getUserPicture(
1751
        $user_id,
1752
        $size = USER_IMAGE_SIZE_MEDIUM,
1753
        $addRandomId = true,
1754
        $userInfo = []
1755
    ) {
1756
        // Make sure userInfo is defined. Otherwise, define it!
1757
        if (empty($userInfo) || !is_array($userInfo) || count($userInfo) == 0) {
1758
            if (empty($user_id)) {
1759
                return '';
1760
            } else {
1761
                $userInfo = api_get_user_info($user_id);
1762
            }
1763
        }
1764
1765
        $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 1761 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...
1766
        $pictureWebFile = $imageWebPath['file'];
1767
        $pictureWebDir = $imageWebPath['dir'];
1768
1769
        $pictureAnonymousSize = '128';
1770
        $gravatarSize = 22;
1771
        $realSizeName = 'small_';
1772
1773
        switch ($size) {
1774
            case USER_IMAGE_SIZE_SMALL:
1775
                $pictureAnonymousSize = '32';
1776
                $realSizeName = 'small_';
1777
                $gravatarSize = 22;
1778
                break;
1779
            case USER_IMAGE_SIZE_MEDIUM:
1780
                $pictureAnonymousSize = '64';
1781
                $realSizeName = 'medium_';
1782
                $gravatarSize = 50;
1783
                break;
1784
            case USER_IMAGE_SIZE_ORIGINAL:
1785
                $pictureAnonymousSize = '128';
1786
                $realSizeName = '';
1787
                $gravatarSize = 200;
1788
                break;
1789
            case USER_IMAGE_SIZE_BIG:
1790
                $pictureAnonymousSize = '128';
1791
                $realSizeName = 'big_';
1792
                $gravatarSize = 200;
1793
                break;
1794
        }
1795
1796
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1797
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1798
        if ($pictureWebFile == 'unknown.jpg' || empty($pictureWebFile)) {
1799
            if ($gravatarEnabled === 'true') {
1800
                $file = self::getGravatar(
1801
                    $imageWebPath['email'],
1802
                    $gravatarSize,
1803
                    api_get_setting('gravatar_type')
1804
                );
1805
1806
                if ($addRandomId) {
1807
                    $file .= '&rand='.uniqid();
1808
                }
1809
1810
                return $file;
1811
            }
1812
1813
            return $anonymousPath;
1814
        }
1815
1816
        $pictureSysPath = self::get_user_picture_path_by_id($user_id, 'system');
1817
1818
        $file = $pictureSysPath['dir'].$realSizeName.$pictureWebFile;
1819
        $picture = '';
1820
        if (file_exists($file)) {
1821
            $picture = $pictureWebDir.$realSizeName.$pictureWebFile;
1822
        } else {
1823
            $file = $pictureSysPath['dir'].$pictureWebFile;
1824
            if (file_exists($file) && !is_dir($file)) {
1825
                $picture = $pictureWebFile['dir'].$pictureWebFile;
1826
            }
1827
        }
1828
1829
        if (empty($picture)) {
1830
            return $anonymousPath;
1831
        }
1832
1833
        if ($addRandomId) {
1834
            $picture .= '?rand='.uniqid();
1835
        }
1836
1837
        return $picture;
1838
    }
1839
1840
    /**
1841
     * Creates new user photos in various sizes of a user, or deletes user photos.
1842
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
1843
     * @param   int $user_id The user internal identification number.
1844
     * @param   string $file The common file name for the newly created photos.
1845
     *                       It will be checked and modified for compatibility with the file system.
1846
     *                       If full name is provided, path component is ignored.
1847
     *                       If an empty name is provided, then old user photos are deleted only,
1848
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1849
     * @param   string $source_file The full system name of the image from which user photos will be created.
1850
     * @param   string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1851
     * @return  mixed Returns the resulting common file name of created images which usually should be stored in database.
1852
     * When deletion is requested returns empty string. In case of internal error or negative validation returns FALSE.
1853
     */
1854
    public static function update_user_picture($user_id, $file = null, $source_file = null, $cropParameters = '')
1855
    {
1856
        if (empty($user_id)) {
1857
            return false;
1858
        }
1859
        $delete = empty($file);
1860
        if (empty($source_file)) {
1861
            $source_file = $file;
1862
        }
1863
1864
        // User-reserved directory where photos have to be placed.
1865
        $path_info = self::getUserPicturePathById($user_id, 'system');
1866
1867
        $path = $path_info['dir'];
1868
1869
        // If this directory does not exist - we create it.
1870
        if (!file_exists($path)) {
1871
            mkdir($path, api_get_permissions_for_new_directories(), true);
1872
        }
1873
1874
        // The old photos (if any).
1875
        $old_file = $path_info['file'];
1876
1877
        // Let us delete them.
1878 View Code Duplication
        if ($old_file != 'unknown.jpg') {
1879
            if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE) {
1880
                $prefix = 'saved_'.date('Y_m_d_H_i_s').'_'.uniqid('').'_';
1881
                @rename($path.'small_'.$old_file, $path.$prefix.'small_'.$old_file);
1882
                @rename($path.'medium_'.$old_file, $path.$prefix.'medium_'.$old_file);
1883
                @rename($path.'big_'.$old_file, $path.$prefix.'big_'.$old_file);
1884
                @rename($path.$old_file, $path.$prefix.$old_file);
1885
            } else {
1886
                @unlink($path.'small_'.$old_file);
1887
                @unlink($path.'medium_'.$old_file);
1888
                @unlink($path.'big_'.$old_file);
1889
                @unlink($path.$old_file);
1890
            }
1891
        }
1892
1893
        // Exit if only deletion has been requested. Return an empty picture name.
1894
        if ($delete) {
1895
            return '';
1896
        }
1897
1898
        // Validation 2.
1899
        $allowed_types = api_get_supported_image_extensions();
1900
        $file = str_replace('\\', '/', $file);
1901
        $filename = (($pos = strrpos($file, '/')) !== false) ? substr($file, $pos + 1) : $file;
1902
        $extension = strtolower(substr(strrchr($filename, '.'), 1));
1903
        if (!in_array($extension, $allowed_types)) {
1904
            return false;
1905
        }
1906
1907
        // This is the common name for the new photos.
1908
        if (KEEP_THE_NAME_WHEN_CHANGE_IMAGE && $old_file != 'unknown.jpg') {
1909
            $old_extension = strtolower(substr(strrchr($old_file, '.'), 1));
1910
            $filename = in_array($old_extension, $allowed_types) ? substr($old_file, 0, -strlen($old_extension)) : $old_file;
1911
            $filename = (substr($filename, -1) == '.') ? $filename.$extension : $filename.'.'.$extension;
1912
        } else {
1913
            $filename = api_replace_dangerous_char($filename);
1914
            if (PREFIX_IMAGE_FILENAME_WITH_UID) {
1915
                $filename = uniqid('').'_'.$filename;
1916
            }
1917
            // We always prefix user photos with user ids, so on setting
1918
            // api_get_setting('split_users_upload_directory') === 'true'
1919
            // the correspondent directories to be found successfully.
1920
            $filename = $user_id.'_'.$filename;
1921
        }
1922
1923
        //Crop the image to adjust 1:1 ratio
1924
        $image = new Image($source_file);
1925
        $image->crop($cropParameters);
1926
1927
        // Storing the new photos in 4 versions with various sizes.
1928
        $userPath = self::getUserPathById($user_id, 'system');
1929
1930
        // If this path does not exist - we create it.
1931
        if (!file_exists($userPath)) {
1932
            mkdir($userPath, api_get_permissions_for_new_directories(), true);
1933
        }
1934
        $small = new Image($source_file);
1935
        $small->resize(32);
1936
        $small->send_image($userPath.'small_'.$filename);
1937
        $medium = new Image($source_file);
1938
        $medium->resize(85);
1939
        $medium->send_image($userPath.'medium_'.$filename);
1940
        $normal = new Image($source_file);
1941
        $normal->resize(200);
1942
        $normal->send_image($userPath.$filename);
1943
1944
        $big = new Image($source_file); // This is the original picture.
1945
        $big->send_image($userPath.'big_'.$filename);
1946
1947
        $result = $small && $medium && $normal && $big;
1948
1949
        return $result ? $filename : false;
1950
    }
1951
1952
    /**
1953
     * Update User extra field file type into {user_folder}/{$extra_field}
1954
     * @param int $user_id          The user internal identification number
1955
     * @param string $extra_field   The $extra_field The extra field name
1956
     * @param null $file            The filename
1957
     * @param null $source_file     The temporal filename
1958
     * @return bool|null            return filename if success, but false
1959
     */
1960
    public static function update_user_extra_file($user_id, $extra_field = '', $file = null, $source_file = null)
1961
    {
1962
        // Add Filter
1963
        $source_file = Security::filter_filename($source_file);
1964
        $file = Security::filter_filename($file);
1965
1966
        if (empty($user_id)) {
1967
            return false;
1968
        }
1969
1970
        if (empty($source_file)) {
1971
            $source_file = $file;
1972
        }
1973
1974
        // User-reserved directory where extra file have to be placed.
1975
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1976
        $path = $path_info['dir'];
1977
        if (!empty($extra_field)) {
1978
            $path .= $extra_field.'/';
1979
        }
1980
        // If this directory does not exist - we create it.
1981
        if (!file_exists($path)) {
1982
            @mkdir($path, api_get_permissions_for_new_directories(), true);
1983
        }
1984
1985
        if (filter_extension($file)) {
1986
            if (@move_uploaded_file($source_file, $path.$file)) {
1987
                if ($extra_field) {
1988
                    return $extra_field.'/'.$file;
1989
                } else {
1990
                    return $file;
1991
                }
1992
            }
1993
        }
1994
        return false; // this should be returned if anything went wrong with the upload
1995
    }
1996
1997
1998
    /**
1999
     * Deletes user photos.
2000
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
2001
     * @param int $user_id            The user internal identification number.
2002
     * @return mixed            Returns empty string on success, FALSE on error.
2003
     */
2004
    public static function delete_user_picture($user_id)
2005
    {
2006
        return self::update_user_picture($user_id);
2007
    }
2008
2009
    /**
2010
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
2011
     * doesn't have any.
2012
     *
2013
     * If there has been a request to remove a production, the function will return
2014
     * without building the list unless forced to do so by the optional second
2015
     * parameter. This increases performance by avoiding to read through the
2016
     * productions on the filesystem before the removal request has been carried
2017
     * out because they'll have to be re-read afterwards anyway.
2018
     *
2019
     * @param   int $user_id    User id
2020
     * @param   bool $force    Optional parameter to force building after a removal request
2021
     * @param   bool $showDelete
2022
     *
2023
     * @return  string A string containing the XHTML code to display the production list, or FALSE
2024
     */
2025
    public static function build_production_list($user_id, $force = false, $showDelete = false)
2026
    {
2027
        if (!$force && !empty($_POST['remove_production'])) {
2028
2029
            return true; // postpone reading from the filesystem
2030
        }
2031
2032
        $productions = self::get_user_productions($user_id);
2033
2034
        if (empty($productions)) {
2035
2036
            return false;
2037
        }
2038
2039
        $production_dir = self::getUserPathById($user_id, 'web');
2040
        $del_image = Display::returnIconPath('delete.png');
2041
        $add_image = Display::returnIconPath('archive.png');
2042
        $del_text = get_lang('Delete');
2043
        $production_list = '';
2044
        if (count($productions) > 0) {
2045
            $production_list = '<div class="files-production"><ul id="productions">';
2046
            foreach ($productions as $file) {
2047
                $production_list .= '<li><img src="'.$add_image.'" /><a href="'.$production_dir.urlencode($file).'" target="_blank">'.htmlentities($file).'</a>';
2048 View Code Duplication
                if ($showDelete) {
2049
                    $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>';
2050
                }
2051
            }
2052
            $production_list .= '</ul></div>';
2053
        }
2054
2055
        return $production_list;
2056
    }
2057
2058
    /**
2059
     * Returns an array with the user's productions.
2060
     *
2061
     * @param    $user_id    User id
2062
     * @return   array  An array containing the user's productions
2063
     */
2064
    public static function get_user_productions($user_id)
2065
    {
2066
        $production_repository = self::getUserPathById($user_id, 'system');
2067
        $productions = array();
2068
2069
        if (is_dir($production_repository)) {
2070
            $handle = opendir($production_repository);
2071
            while ($file = readdir($handle)) {
2072
                if ($file == '.' ||
2073
                    $file == '..' ||
2074
                    $file == '.htaccess' ||
2075
                    is_dir($production_repository.$file)
2076
                ) {
2077
                    // skip current/parent directory and .htaccess
2078
                    continue;
2079
                }
2080
2081
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
2082
                    // User's photos should not be listed as productions.
2083
                    continue;
2084
                }
2085
                $productions[] = $file;
2086
            }
2087
        }
2088
2089
        return $productions;
2090
    }
2091
2092
    /**
2093
     * Remove a user production.
2094
     *
2095
     * @param int $user_id        User id
2096
     * @param string $production    The production to remove
2097
     */
2098
    public static function remove_user_production($user_id, $production)
2099
    {
2100
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
2101
        $production_file = $production_path['dir'].$production;
2102
        if (is_file($production_file)) {
2103
            unlink($production_file);
2104
            return true;
2105
        }
2106
        return false;
2107
    }
2108
2109
    /**
2110
     * Update an extra field value for a given user
2111
     * @param    integer   $userId User ID
2112
     * @param    string    $variable Field variable name
2113
     * @param    string    $value Field value
2114
     *
2115
     * @return    boolean    true if field updated, false otherwise
2116
     */
2117 View Code Duplication
    public static function update_extra_field_value($userId, $variable, $value = '')
2118
    {
2119
        $extraFieldValue = new ExtraFieldValue('user');
2120
        $params = [
2121
            'item_id' => $userId,
2122
            'variable' => $variable,
2123
            'value' => $value
2124
        ];
2125
2126
        return $extraFieldValue->save($params);
2127
    }
2128
2129
    /**
2130
     * Get an array of extra fields with field details (type, default value and options)
2131
     * @param    integer    Offset (from which row)
2132
     * @param    integer    Number of items
2133
     * @param    integer    Column on which sorting is made
2134
     * @param    string    Sorting direction
2135
     * @param    boolean    Optional. Whether we get all the fields or just the visible ones
2136
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
2137
     * @return    array    Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
2138
     */
2139
    public static function get_extra_fields(
2140
        $from = 0,
2141
        $number_of_items = 0,
2142
        $column = 5,
2143
        $direction = 'ASC',
2144
        $all_visibility = true,
2145
        $field_filter = null
2146
    ) {
2147
        $fields = array();
2148
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2149
        $t_ufo = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
2150
        $columns = array(
2151
            'id',
2152
            'variable',
2153
            'field_type',
2154
            'display_text',
2155
            'default_value',
2156
            'field_order',
2157
            'filter'
2158
        );
2159
        $column = intval($column);
2160
        $sort_direction = '';
2161
        if (in_array(strtoupper($direction), array('ASC', 'DESC'))) {
2162
            $sort_direction = strtoupper($direction);
2163
        }
2164
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
2165
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
2166
        if (!$all_visibility) {
2167
            $sqlf .= " AND visible_to_self = 1 ";
2168
        }
2169
        if (!is_null($field_filter)) {
2170
            $field_filter = intval($field_filter);
2171
            $sqlf .= " AND filter = $field_filter ";
2172
        }
2173
        $sqlf .= " ORDER BY ".$columns[$column]." $sort_direction ";
2174
        if ($number_of_items != 0) {
2175
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
2176
        }
2177
        $resf = Database::query($sqlf);
2178
        if (Database::num_rows($resf) > 0) {
2179
            while ($rowf = Database::fetch_array($resf)) {
2180
                $fields[$rowf['id']] = array(
2181
                    0 => $rowf['id'],
2182
                    1 => $rowf['variable'],
2183
                    2 => $rowf['field_type'],
2184
                    3 => empty($rowf['display_text']) ? '' : $rowf['display_text'],
2185
                    4 => $rowf['default_value'],
2186
                    5 => $rowf['field_order'],
2187
                    6 => $rowf['visible_to_self'],
2188
                    7 => $rowf['changeable'],
2189
                    8 => $rowf['filter'],
2190
                    9 => array(),
2191
                    10 => '<a name="'.$rowf['id'].'"></a>',
2192
                );
2193
2194
                $sqlo = "SELECT * FROM $t_ufo
2195
                         WHERE field_id = ".$rowf['id']."
2196
                         ORDER BY option_order ASC";
2197
                $reso = Database::query($sqlo);
2198
                if (Database::num_rows($reso) > 0) {
2199
                    while ($rowo = Database::fetch_array($reso)) {
2200
                        $fields[$rowf['id']][9][$rowo['id']] = array(
2201
                            0 => $rowo['id'],
2202
                            1 => $rowo['option_value'],
2203
                            2 => empty($rowo['display_text']) ? '' : $rowo['display_text'],
2204
                            3 => $rowo['option_order']
2205
                        );
2206
                    }
2207
                }
2208
            }
2209
        }
2210
2211
        return $fields;
2212
    }
2213
2214
    /**
2215
     * Build a list of extra file already uploaded in $user_folder/{$extra_field}/
2216
     * @param $user_id
2217
     * @param $extra_field
2218
     * @param bool $force
2219
     * @param bool $showDelete
2220
     * @return bool|string
2221
     */
2222
    public static function build_user_extra_file_list($user_id, $extra_field, $force = false, $showDelete = false)
2223
    {
2224
        if (!$force && !empty($_POST['remove_'.$extra_field])) {
2225
            return true; // postpone reading from the filesystem
2226
        }
2227
2228
        $extra_files = self::get_user_extra_files($user_id, $extra_field);
2229
        if (empty($extra_files)) {
2230
            return false;
2231
        }
2232
2233
        $path_info = self::get_user_picture_path_by_id($user_id, 'web');
2234
        $path = $path_info['dir'];
2235
        $del_image = Display::returnIconPath('delete.png');
2236
2237
        $del_text = get_lang('Delete');
2238
        $extra_file_list = '';
2239
        if (count($extra_files) > 0) {
2240
            $extra_file_list = '<div class="files-production"><ul id="productions">';
2241
            foreach ($extra_files as $file) {
2242
                $filename = substr($file, strlen($extra_field) + 1);
2243
                $extra_file_list .= '<li>'.Display::return_icon('archive.png').'<a href="'.$path.$extra_field.'/'.urlencode($filename).'" target="_blank">'.htmlentities($filename).'</a> ';
2244 View Code Duplication
                if ($showDelete) {
2245
                    $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>';
2246
                }
2247
            }
2248
            $extra_file_list .= '</ul></div>';
2249
        }
2250
2251
        return $extra_file_list;
2252
    }
2253
2254
    /**
2255
     * Get valid filenames in $user_folder/{$extra_field}/
2256
     * @param $user_id
2257
     * @param $extra_field
2258
     * @param bool $full_path
2259
     * @return array
2260
     */
2261
    public static function get_user_extra_files($user_id, $extra_field, $full_path = false)
2262
    {
2263
        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...
2264
            // Nothing to do
2265
        } else {
2266
            $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2267
            $path = $path_info['dir'];
2268
        }
2269
        $extra_data = self::get_extra_user_data_by_field($user_id, $extra_field);
2270
        $extra_files = $extra_data[$extra_field];
2271
        if (is_array($extra_files)) {
2272
            foreach ($extra_files as $key => $value) {
2273
                if (!$full_path) {
2274
                    // Relative path from user folder
2275
                    $files[] = $value;
2276
                } else {
2277
                    $files[] = $path.$value;
2278
                }
2279
            }
2280
        } elseif (!empty($extra_files)) {
2281
            if (!$full_path) {
2282
                // Relative path from user folder
2283
                $files[] = $extra_files;
2284
            } else {
2285
                $files[] = $path.$extra_files;
2286
            }
2287
        }
2288
2289
        return $files; // can be an empty array
2290
    }
2291
2292
    /**
2293
     * Remove an {$extra_file} from the user folder $user_folder/{$extra_field}/
2294
     * @param $user_id
2295
     * @param $extra_field
2296
     * @param $extra_file
2297
     * @return bool
2298
     */
2299
    public static function remove_user_extra_file($user_id, $extra_field, $extra_file)
2300
    {
2301
        $extra_file = Security::filter_filename($extra_file);
2302
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2303
        if (strpos($extra_file, $extra_field) !== false) {
2304
            $path_extra_file = $path_info['dir'].$extra_file;
2305
        } else {
2306
            $path_extra_file = $path_info['dir'].$extra_field.'/'.$extra_file;
2307
        }
2308
        if (is_file($path_extra_file)) {
2309
            unlink($path_extra_file);
2310
            return true;
2311
        }
2312
        return false;
2313
    }
2314
2315
    /**
2316
     * Creates a new extra field
2317
     * @param    string    $variable Field's internal variable name
2318
     * @param    int       $fieldType  Field's type
2319
     * @param    string    $displayText Field's language var name
2320
     * @param    string    $default Field's default value
2321
     * @return int
2322
     */
2323 View Code Duplication
    public static function create_extra_field($variable, $fieldType, $displayText, $default)
2324
    {
2325
        $extraField = new ExtraField('user');
2326
        $params = [
2327
            'variable' => $variable,
2328
            'field_type' => $fieldType,
2329
            'display_text' => $displayText,
2330
            'default_value' => $default
2331
        ];
2332
2333
        return $extraField->save($params);
2334
    }
2335
2336
    /**
2337
     * Check if a field is available
2338
     * @param    string    $variable
2339
     * @return    boolean
2340
     */
2341
    public static function is_extra_field_available($variable)
2342
    {
2343
        $extraField = new ExtraField('user');
2344
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2345
2346
        return !empty($data) ? true : false;
2347
    }
2348
2349
    /**
2350
     * Gets user extra fields data
2351
     * @param    integer    User ID
2352
     * @param    boolean    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2353
     * @param    boolean    Whether to return invisible fields as well
2354
     * @param    boolean    Whether to split multiple-selection fields or not
2355
     * @return    array    Array of fields => value for the given user
2356
     */
2357
    public static function get_extra_user_data(
2358
        $user_id,
2359
        $prefix = false,
2360
        $all_visibility = true,
2361
        $splitmultiple = false,
2362
        $field_filter = null
2363
    ) {
2364
        // A sanity check.
2365 View Code Duplication
        if (empty($user_id)) {
2366
            $user_id = 0;
2367
        } else {
2368
            if ($user_id != strval(intval($user_id)))
2369
                return array();
2370
        }
2371
        $extra_data = array();
2372
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2373
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2374
        $user_id = intval($user_id);
2375
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2376
                FROM $t_uf f
2377
                WHERE
2378
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2379
                ";
2380
        $filter_cond = '';
2381
2382
        if (!$all_visibility) {
2383
            if (isset($field_filter)) {
2384
                $field_filter = intval($field_filter);
2385
                $filter_cond .= " AND filter = $field_filter ";
2386
            }
2387
            $sql .= " AND f.visible_to_self = 1 $filter_cond ";
2388
        } else {
2389
            if (isset($field_filter)) {
2390
                $field_filter = intval($field_filter);
2391
                $sql .= " AND filter = $field_filter ";
2392
            }
2393
        }
2394
2395
        $sql .= " ORDER BY f.field_order";
2396
2397
        $res = Database::query($sql);
2398
        if (Database::num_rows($res) > 0) {
2399
            while ($row = Database::fetch_array($res)) {
2400
                if ($row['type'] == self::USER_FIELD_TYPE_TAG) {
2401
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2402
                    $extra_data['extra_'.$row['fvar']] = $tags;
2403
                } else {
2404
                    $sqlu = "SELECT value as fval
2405
                            FROM $t_ufv
2406
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2407
                    $resu = Database::query($sqlu);
2408
                    // get default value
2409
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2410
                               WHERE id=".$row['id'];
2411
                    $res_df = Database::query($sql_df);
2412
2413
                    if (Database::num_rows($resu) > 0) {
2414
                        $rowu = Database::fetch_array($resu);
2415
                        $fval = $rowu['fval'];
2416
                        if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2417
                            $fval = explode(';', $rowu['fval']);
2418
                        }
2419
                    } else {
2420
                        $row_df = Database::fetch_array($res_df);
2421
                        $fval = $row_df['fval_df'];
2422
                    }
2423
                    // We get here (and fill the $extra_data array) even if there
2424
                    // is no user with data (we fill it with default values)
2425
                    if ($prefix) {
2426 View Code Duplication
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2427
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2428
                        } else {
2429
                            $extra_data['extra_'.$row['fvar']] = $fval;
2430
                        }
2431 View Code Duplication
                    } else {
2432
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2433
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2434
                        } else {
2435
                            $extra_data[$row['fvar']] = $fval;
2436
                        }
2437
                    }
2438
                }
2439
            }
2440
        }
2441
2442
        return $extra_data;
2443
    }
2444
2445
    /** Get extra user data by field
2446
     * @param int    user ID
2447
     * @param string the internal variable name of the field
2448
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2449
     */
2450
    public static function get_extra_user_data_by_field(
2451
        $user_id,
2452
        $field_variable,
2453
        $prefix = false,
2454
        $all_visibility = true,
2455
        $splitmultiple = false
2456
    ) {
2457
        // A sanity check.
2458 View Code Duplication
        if (empty($user_id)) {
2459
            $user_id = 0;
2460
        } else {
2461
            if ($user_id != strval(intval($user_id)))
2462
                return array();
2463
        }
2464
        $extra_data = array();
2465
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2466
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2467
        $user_id = intval($user_id);
2468
2469
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2470
                FROM $t_uf f
2471
                WHERE f.variable = '$field_variable' ";
2472
2473
        if (!$all_visibility) {
2474
            $sql .= " AND f.visible_to_self = 1 ";
2475
        }
2476
2477
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2478
2479
        $sql .= " ORDER BY f.field_order";
2480
2481
        $res = Database::query($sql);
2482
        if (Database::num_rows($res) > 0) {
2483
            while ($row = Database::fetch_array($res)) {
2484
                $sqlu = "SELECT value as fval FROM $t_ufv v INNER JOIN $t_uf f
2485
                         ON (v.field_id = f.id)
2486
                         WHERE
2487
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2488
                            field_id = ".$row['id']." AND
2489
                            item_id = ".$user_id;
2490
                $resu = Database::query($sqlu);
2491
                $fval = '';
2492 View Code Duplication
                if (Database::num_rows($resu) > 0) {
2493
                    $rowu = Database::fetch_array($resu);
2494
                    $fval = $rowu['fval'];
2495
                    if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2496
                        $fval = explode(';', $rowu['fval']);
2497
                    }
2498
                }
2499
                if ($prefix) {
2500
                    $extra_data['extra_'.$row['fvar']] = $fval;
2501
                } else {
2502
                    $extra_data[$row['fvar']] = $fval;
2503
                }
2504
            }
2505
        }
2506
2507
        return $extra_data;
2508
    }
2509
2510
    /**
2511
     * Get the extra field information for a certain field (the options as well)
2512
     * @param  int     $variable The name of the field we want to know everything about
2513
     * @return array   Array containing all the information about the extra profile field
2514
     * (first level of array contains field details, then 'options' sub-array contains options details,
2515
     * as returned by the database)
2516
     * @author Julio Montoya
2517
     * @since v1.8.6
2518
     */
2519
    public static function get_extra_field_information_by_name($variable)
2520
    {
2521
        $extraField = new ExtraField('user');
2522
2523
        return $extraField->get_handler_field_info_by_field_variable($variable);
2524
    }
2525
2526
    /**
2527
     * Get the extra field information for user tag (the options as well)
2528
     * @param  int     $variable The name of the field we want to know everything about
2529
     * @return array   Array containing all the information about the extra profile field
2530
     * (first level of array contains field details, then 'options' sub-array contains options details,
2531
     * as returned by the database)
2532
     * @author José Loguercio
2533
     * @since v1.11.0
2534
     */
2535
    public static function get_extra_field_tags_information_by_name($variable)
2536
    {
2537
        $extraField = new ExtraField('user');
2538
2539
        return $extraField->get_handler_field_info_by_tags($variable);
2540
    }
2541
2542
    /**
2543
     * @param string $type
2544
     *
2545
     * @return array
2546
     */
2547
    public static function get_all_extra_field_by_type($type)
2548
    {
2549
        $extraField = new ExtraField('user');
2550
2551
        return $extraField->get_all_extra_field_by_type($type);
2552
    }
2553
2554
    /**
2555
     * Get all the extra field information of a certain field (also the options)
2556
     *
2557
     * @param int $fieldId the ID of the field we want to know everything of
2558
     * @return array $return containing all th information about the extra profile field
2559
     * @author Julio Montoya
2560
     * @deprecated
2561
     * @since v1.8.6
2562
     */
2563
    public static function get_extra_field_information($fieldId)
2564
    {
2565
        $extraField = new ExtraField('user');
2566
2567
        return $extraField->getFieldInfoByFieldId($fieldId);
2568
    }
2569
2570
    /**
2571
     * Get extra user data by value
2572
     * @param string $variable the internal variable name of the field
2573
     * @param string $value the internal value of the field
2574
     * @param bool $all_visibility
2575
     *
2576
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2577
     */
2578
     public static function get_extra_user_data_by_value($variable, $value, $all_visibility = true)
2579
    {
2580
        $extraFieldValue = new ExtraFieldValue('user');
2581
        $extraField = new ExtraField('user');
2582
2583
        $info = $extraField->get_handler_field_info_by_field_variable($variable);
2584
2585
        if (false === $info) {
2586
            return [];
2587
        }
2588
2589
        $data = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
2590
            $variable,
2591
            $value,
2592
            false,
2593
            false,
2594
            true
2595
        );
2596
2597
        $result = [];
2598
        if (!empty($data)) {
2599
            foreach ($data as $item) {
2600
                $result[] = $item['item_id'];
2601
            }
2602
        }
2603
2604
        return $result;
2605
    }
2606
2607
    /**
2608
     * Get extra user data by tags value
2609
     *
2610
     * @param int $fieldId the ID of the field we want to know everything of
2611
     * @param string $tag the tag name for search
2612
     * @return array with extra data info of a user
2613
     * @author José Loguercio
2614
     * @since v1.11.0
2615
     */
2616
    public static function get_extra_user_data_by_tags($fieldId, $tag)
2617
    {
2618
        $extraField = new ExtraField('user');
2619
        $result = $extraField->getAllUserPerTag($fieldId, $tag);
2620
        $array = [];
2621
        foreach ($result as $index => $user) {
2622
            $array[] = $user['user_id'];
2623
        }
2624
        return $array;
2625
    }
2626
2627
    /**
2628
     * Get extra user data by field variable
2629
     * @param string    $variable field variable
2630
     * @return array    data
2631
     */
2632
    public static function get_extra_user_data_by_field_variable($variable)
2633
    {
2634
        $extra_information_by_variable = self::get_extra_field_information_by_name($variable);
2635
        $field_id = intval($extra_information_by_variable['id']);
2636
2637
        $extraField = new ExtraFieldValue('user');
2638
        $data = $extraField->getValuesByFieldId($field_id);
2639
2640
        if (!empty($data) > 0) {
2641
            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...
2642
                $user_id = $row['item_id'];
2643
                $data[$user_id] = $row;
2644
            }
2645
        }
2646
2647
        return $data;
2648
    }
2649
2650
    /**
2651
     * Get extra user data tags by field variable
2652
     *
2653
     * @param string $variable field variable
2654
     * @return array
2655
     */
2656
    public static function get_extra_user_data_for_tags($variable)
2657
    {
2658
        $data = self::get_extra_field_tags_information_by_name($variable);
2659
2660
        return $data;
2661
    }
2662
2663
    /**
2664
     * Gives a list of [session_category][session_id] for the current user.
2665
     * @param integer $user_id
2666
     * @param boolean $is_time_over whether to fill the first element or not (to give space for courses out of categories)
2667
     * @param boolean $ignore_visibility_for_admins optional true if limit time from session is over, false otherwise
2668
     * @param boolean $ignoreTimeLimit ignore time start/end
2669
     * @return array  list of statuses [session_category][session_id]
2670
     *
2671
     * @todo ensure multiple access urls are managed correctly
2672
     */
2673
    public static function get_sessions_by_category(
2674
        $user_id,
2675
        $is_time_over = true,
2676
        $ignore_visibility_for_admins = false,
2677
        $ignoreTimeLimit = false
2678
    ) {
2679
        if ($user_id != strval(intval($user_id))) {
2680
            return array();
2681
        }
2682
2683
        // Get the list of sessions per user
2684
        $now = new DateTime('now', new DateTimeZone('UTC'));
2685
2686
        // LEFT JOIN is used for session_rel_course_rel_user because an inner
2687
        // join would not catch session-courses where the user is general
2688
        // session coach but which do not have students nor coaches registered
2689
        $dql = "SELECT DISTINCT
2690
                    s.id,
2691
                    s.name,
2692
                    s.accessStartDate AS access_start_date,
2693
                    s.accessEndDate AS access_end_date,
2694
                    s.duration,
2695
                    sc.id AS session_category_id,
2696
                    sc.name AS session_category_name,
2697
                    sc.dateStart AS session_category_date_start,
2698
                    sc.dateEnd AS session_category_date_end,
2699
                    s.coachAccessStartDate AS coach_access_start_date,
2700
                    s.coachAccessEndDate AS coach_access_end_date
2701
                FROM ChamiloCoreBundle:Session AS s
2702
                LEFT JOIN ChamiloCoreBundle:SessionRelCourseRelUser AS scu WITH scu.session = s
2703
                INNER JOIN ChamiloCoreBundle:AccessUrlRelSession AS url WITH url.session = s
2704
                LEFT JOIN ChamiloCoreBundle:SessionCategory AS sc WITH s.category = sc
2705
                WHERE (scu.user = :user OR s.generalCoach = :user) AND url.url = :url
2706
                ORDER BY sc.name, s.name";
2707
2708
        $dql = Database::getManager()
2709
            ->createQuery($dql)
2710
            ->setParameters(
2711
                ['user' => $user_id, 'url' => api_get_current_access_url_id()]
2712
            )
2713
        ;
2714
2715
        $sessionData = $dql->getResult();
2716
        $categories = [];
2717
2718
        foreach ($sessionData as $row) {
2719
            $session_id = $row['id'];
2720
            $coachList = SessionManager::getCoachesBySession($session_id);
2721
2722
            $categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
2723
            $categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
2724
2725
            $courseList = self::get_courses_list_by_session(
2726
                $user_id,
2727
                $session_id
2728
            );
2729
            $daysLeft = SessionManager::getDayLeftInSession($row, $user_id);
2730
2731
            // User portal filters:
2732
            if ($ignoreTimeLimit === false) {
2733
                if ($is_time_over) {
2734
                    // History
2735
                    if ($row['duration']) {
2736
                        if ($daysLeft >= 0) {
2737
                            continue;
2738
                        }
2739
                    } else {
2740
                        if (empty($row['access_end_date'])) {
2741
                            continue;
2742
                        } else {
2743
                            if ($row['access_end_date'] > $now) {
2744
                                continue;
2745
                            }
2746
                        }
2747
                    }
2748
                } else {
2749
                    // Current user portal
2750
                    $isGeneralCoach = SessionManager::user_is_general_coach($user_id, $row['id']);
2751
                    $isCoachOfCourse = in_array($user_id, $coachList);
2752
2753
                    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...
2754
                        // Teachers can access the session depending in the access_coach date
2755
                    } else {
2756
                        if ($row['duration']) {
2757
                            if ($daysLeft <= 0) {
2758
                                continue;
2759
                            }
2760
                        } else {
2761
                            if (isset($row['access_end_date']) &&
2762
                                !empty($row['access_end_date'])
2763
                            ) {
2764
                                if ($row['access_end_date'] <= $now) {
2765
                                    continue;
2766
                                }
2767
                            }
2768
                        }
2769
                    }
2770
                }
2771
            }
2772
2773
            $categories[$row['session_category_id']]['session_category'] = array(
2774
                'id' => $row['session_category_id'],
2775
                'name' => $row['session_category_name'],
2776
                'date_start' => $categoryStart,
2777
                'date_end' => $categoryEnd
2778
            );
2779
2780
            $visibility = api_get_session_visibility(
2781
                $session_id,
2782
                null,
2783
                $ignore_visibility_for_admins
2784
            );
2785
2786 View Code Duplication
            if ($visibility != SESSION_VISIBLE) {
2787
                // Course Coach session visibility.
2788
                $blockedCourseCount = 0;
2789
                $closedVisibilityList = array(
2790
                    COURSE_VISIBILITY_CLOSED,
2791
                    COURSE_VISIBILITY_HIDDEN
2792
                );
2793
2794
                foreach ($courseList as $course) {
2795
                    // Checking session visibility
2796
                    $sessionCourseVisibility = api_get_session_visibility(
2797
                        $session_id,
2798
                        $course['real_id'],
2799
                        $ignore_visibility_for_admins
2800
                    );
2801
2802
                    $courseIsVisible = !in_array(
2803
                        $course['visibility'],
2804
                        $closedVisibilityList
2805
                    );
2806
                    if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
2807
                        $blockedCourseCount++;
2808
                    }
2809
                }
2810
2811
                // If all courses are blocked then no show in the list.
2812
                if ($blockedCourseCount === count($courseList)) {
2813
                    $visibility = SESSION_INVISIBLE;
2814
                } else {
2815
                    $visibility = $sessionCourseVisibility;
2816
                }
2817
            }
2818
2819
            switch ($visibility) {
2820
                case SESSION_VISIBLE_READ_ONLY:
2821
                case SESSION_VISIBLE:
2822
                case SESSION_AVAILABLE:
2823
                    break;
2824
                case SESSION_INVISIBLE:
2825
                    if ($ignore_visibility_for_admins === false) {
2826
                        continue 2;
2827
                    }
2828
            }
2829
2830
            $categories[$row['session_category_id']]['sessions'][$row['id']] = array(
2831
                'session_name' => $row['name'],
2832
                'session_id' => $row['id'],
2833
                'access_start_date' => $row['access_start_date'] ? $row['access_start_date']->format('Y-m-d H:i:s') : null,
2834
                'access_end_date' => $row['access_end_date'] ? $row['access_end_date']->format('Y-m-d H:i:s') : null,
2835
                'coach_access_start_date' => $row['coach_access_start_date'] ? $row['coach_access_start_date']->format('Y-m-d H:i:s') : null,
2836
                'coach_access_end_date' => $row['coach_access_end_date'] ? $row['coach_access_end_date']->format('Y-m-d H:i:s') : null,
2837
                'display_start_date' => $row['display_start_date'] ? $row['display_start_date']->format(
2838
                    'Y-m-d H:i:s'
2839
                ) : null,
2840
                'display_end_date' => $row['display_end_date'] ? $row['display_end_date']->format(
2841
                    'Y-m-d H:i:s'
2842
                ) : null,
2843
                'courses' => $courseList
2844
            );
2845
        }
2846
2847
        return $categories;
2848
    }
2849
2850
    /**
2851
     * Gives a list of [session_id-course_code] => [status] for the current user.
2852
     * @param integer $user_id
2853
     * @param int $sessionLimit
2854
     * @return array  list of statuses (session_id-course_code => status)
2855
     */
2856
    public static function get_personal_session_course_list($user_id, $sessionLimit = null)
2857
    {
2858
        // Database Table Definitions
2859
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2860
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2861
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2862
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2863
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2864
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2865
2866
        if ($user_id != strval(intval($user_id))) {
2867
            return array();
2868
        }
2869
2870
        // We filter the courses from the URL
2871
        $join_access_url = $where_access_url = '';
2872
2873
        if (api_get_multiple_access_url()) {
2874
            $access_url_id = api_get_current_access_url_id();
2875
            if ($access_url_id != -1) {
2876
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2877
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2878
                $where_access_url = " AND access_url_id = $access_url_id ";
2879
            }
2880
        }
2881
2882
        // Courses in which we subscribed out of any session
2883
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
2884
2885
        $sql = "SELECT
2886
                    course.code,
2887
                    course_rel_user.status course_rel_status,
2888
                    course_rel_user.sort sort,
2889
                    course_rel_user.user_course_cat user_course_cat
2890
                 FROM $tbl_course_user course_rel_user
2891
                 LEFT JOIN $tbl_course course
2892
                 ON course.id = course_rel_user.c_id
2893
                 LEFT JOIN $tbl_user_course_category user_course_category
2894
                 ON course_rel_user.user_course_cat = user_course_category.id
2895
                 $join_access_url
2896
                 WHERE
2897
                    course_rel_user.user_id = '".$user_id."' AND
2898
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2899
                    $where_access_url
2900
                 ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
2901
2902
        $course_list_sql_result = Database::query($sql);
2903
2904
        $personal_course_list = array();
2905
        if (Database::num_rows($course_list_sql_result) > 0) {
2906
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2907
                $course_info = api_get_course_info($result_row['code']);
2908
                $result_row['course_info'] = $course_info;
2909
                $personal_course_list[] = $result_row;
2910
            }
2911
        }
2912
2913
        $coachCourseConditions = null;
2914
2915
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2916
        if (api_is_allowed_to_create_course()) {
2917
            $sessionListFromCourseCoach = array();
2918
            $sql = " SELECT DISTINCT session_id
2919
                    FROM $tbl_session_course_user
2920
                    WHERE user_id = $user_id AND status = 2 ";
2921
2922
            $result = Database::query($sql);
2923
            if (Database::num_rows($result)) {
2924
                $result = Database::store_result($result);
2925
                foreach ($result as $session) {
2926
                    $sessionListFromCourseCoach[] = $session['session_id'];
2927
                }
2928
            }
2929
            if (!empty($sessionListFromCourseCoach)) {
2930
                $condition = implode("','", $sessionListFromCourseCoach);
2931
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2932
            }
2933
        }
2934
2935
        // Get the list of sessions where the user is subscribed
2936
        // This is divided into two different queries
2937
        $sessions = array();
2938
2939
        $sessionLimitRestriction = '';
2940
        if (!empty($sessionLimit)) {
2941
            $sessionLimit = (int) $sessionLimit;
2942
            $sessionLimitRestriction = "LIMIT $sessionLimit";
2943
        }
2944
2945
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2946
                FROM $tbl_session_user su INNER JOIN $tbl_session s
2947
                ON (s.id = su.session_id)
2948
                WHERE (
2949
                    su.user_id = $user_id AND
2950
                    su.relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2951
                )
2952
                $coachCourseConditions
2953
                ORDER BY access_start_date, access_end_date, name
2954
                $sessionLimitRestriction
2955
        ";
2956
2957
        $result = Database::query($sql);
2958 View Code Duplication
        if (Database::num_rows($result) > 0) {
2959
            while ($row = Database::fetch_assoc($result)) {
2960
                $sessions[$row['id']] = $row;
2961
            }
2962
        }
2963
2964
        $sql = "SELECT DISTINCT
2965
                id, name, access_start_date, access_end_date
2966
                FROM $tbl_session s
2967
                WHERE (
2968
                    id_coach = $user_id
2969
                )
2970
                $coachCourseConditions
2971
                ORDER BY access_start_date, access_end_date, name";
2972
2973
        $result = Database::query($sql);
2974
        if (Database::num_rows($result) > 0) {
2975
            while ($row = Database::fetch_assoc($result)) {
2976
                if (empty($sessions[$row['id']])) {
2977
                    $sessions[$row['id']] = $row;
2978
                }
2979
            }
2980
        }
2981
2982
        if (api_is_allowed_to_create_course()) {
2983
            foreach ($sessions as $enreg) {
2984
                $session_id = $enreg['id'];
2985
                $session_visibility = api_get_session_visibility($session_id);
2986
2987
                if ($session_visibility == SESSION_INVISIBLE) {
2988
                    continue;
2989
                }
2990
2991
                // This query is horribly slow when more than a few thousand
2992
                // users and just a few sessions to which they are subscribed
2993
                $sql = "SELECT DISTINCT
2994
                        course.code code,
2995
                        course.title i,
2996
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
2997
                        email, course.course_language l,
2998
                        1 sort,
2999
                        category_code user_course_cat,
3000
                        access_start_date,
3001
                        access_end_date,
3002
                        session.id as session_id,
3003
                        session.name as session_name
3004
                    FROM $tbl_session_course_user as session_course_user
3005
                        INNER JOIN $tbl_course AS course
3006
                            ON course.id = session_course_user.c_id
3007
                        INNER JOIN $tbl_session as session
3008
                            ON session.id = session_course_user.session_id
3009
                        LEFT JOIN $tbl_user as user
3010
                            ON user.id = session_course_user.user_id OR session.id_coach = user.id
3011
                    WHERE
3012
                        session_course_user.session_id = $session_id AND (
3013
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
3014
                            OR session.id_coach = $user_id
3015
                        )
3016
                    ORDER BY i";
3017
                $course_list_sql_result = Database::query($sql);
3018 View Code Duplication
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3019
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
3020
                    $key = $result_row['session_id'].' - '.$result_row['code'];
3021
                    $personal_course_list[$key] = $result_row;
3022
                }
3023
            }
3024
        }
3025
3026
        foreach ($sessions as $enreg) {
3027
            $session_id = $enreg['id'];
3028
            $session_visibility = api_get_session_visibility($session_id);
3029
            if ($session_visibility == SESSION_INVISIBLE) {
3030
                continue;
3031
            }
3032
3033
            /* This query is very similar to the above query,
3034
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
3035
            $sql = "SELECT DISTINCT
3036
                course.code code,
3037
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
3038
                email,
3039
                course.course_language l,
3040
                1 sort,
3041
                category_code user_course_cat,
3042
                access_start_date,
3043
                access_end_date,
3044
                session.id as session_id,
3045
                session.name as session_name,
3046
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
3047
            FROM $tbl_session_course_user as session_course_user
3048
            INNER JOIN $tbl_course AS course
3049
            ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
3050
            INNER JOIN $tbl_session as session 
3051
            ON session_course_user.session_id = session.id
3052
            LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
3053
            WHERE session_course_user.user_id = $user_id
3054
            ORDER BY i";
3055
3056
            $course_list_sql_result = Database::query($sql);
3057 View Code Duplication
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3058
                $result_row['course_info'] = api_get_course_info($result_row['code']);
3059
                $key = $result_row['session_id'].' - '.$result_row['code'];
3060
                if (!isset($personal_course_list[$key])) {
3061
                    $personal_course_list[$key] = $result_row;
3062
                }
3063
            }
3064
        }
3065
3066
        return $personal_course_list;
3067
    }
3068
3069
    /**
3070
     * Gives a list of courses for the given user in the given session
3071
     * @param integer $user_id
3072
     * @param integer $session_id
3073
     * @return array  list of statuses (session_id-course_code => status)
3074
     */
3075
    public static function get_courses_list_by_session($user_id, $session_id)
3076
    {
3077
        // Database Table Definitions
3078
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3079
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
3080
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3081
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3082
3083
        $user_id = intval($user_id);
3084
        $session_id = intval($session_id);
3085
        //we filter the courses from the URL
3086
        $join_access_url = $where_access_url = '';
3087
3088
        if (api_get_multiple_access_url()) {
3089
            $urlId = api_get_current_access_url_id();
3090
            if ($urlId != -1) {
3091
                $tbl_url_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3092
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
3093
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
3094
            }
3095
        }
3096
3097
        /* This query is very similar to the query below, but it will check the
3098
        session_rel_course_user table if there are courses registered
3099
        to our user or not */
3100
        $sql = "SELECT DISTINCT
3101
                    c.visibility,
3102
                    c.id as real_id,
3103
                    c.code as course_code,
3104
                    sc.position
3105
                FROM $tbl_session_course_user as scu
3106
                INNER JOIN $tbl_session_course sc
3107
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3108
                INNER JOIN $tableCourse as c
3109
                ON (scu.c_id = c.id)
3110
                $join_access_url
3111
                WHERE
3112
                    scu.user_id = $user_id AND
3113
                    scu.session_id = $session_id
3114
                    $where_access_url
3115
                ORDER BY sc.position ASC, c.id";
3116
3117
        $personal_course_list = array();
3118
        $courses = array();
3119
3120
        $result = Database::query($sql);
3121 View Code Duplication
        if (Database::num_rows($result) > 0) {
3122
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3123
                $result_row['status'] = 5;
3124
                if (!in_array($result_row['real_id'], $courses)) {
3125
                    $personal_course_list[] = $result_row;
3126
                    $courses[] = $result_row['real_id'];
3127
                }
3128
            }
3129
        }
3130
3131
        if (api_is_allowed_to_create_course()) {
3132
            $sql = "SELECT DISTINCT
3133
                        c.visibility, 
3134
                        c.id as real_id,
3135
                        c.code as course_code,
3136
                        sc.position
3137
                    FROM $tbl_session_course_user as scu
3138
                    INNER JOIN $tbl_session as s
3139
                    ON (scu.session_id = s.id)
3140
                    INNER JOIN $tbl_session_course sc
3141
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3142
                    INNER JOIN $tableCourse as c
3143
                    ON (scu.c_id = c.id)
3144
                    $join_access_url
3145
                    WHERE
3146
                      s.id = $session_id AND
3147
                      (
3148
                        (scu.user_id = $user_id AND scu.status = 2) OR
3149
                        s.id_coach = $user_id
3150
                      )
3151
                    $where_access_url
3152
                    ORDER BY sc.position ASC";
3153
            $result = Database::query($sql);
3154
3155 View Code Duplication
            if (Database::num_rows($result) > 0) {
3156
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3157
                    $result_row['status'] = 2;
3158
                    if (!in_array($result_row['real_id'], $courses)) {
3159
                        $personal_course_list[] = $result_row;
3160
                        $courses[] = $result_row['real_id'];
3161
                    }
3162
                }
3163
            }
3164
        }
3165
3166
        if (api_is_drh()) {
3167
            $sessionList = SessionManager::get_sessions_followed_by_drh($user_id);
3168
            $sessionList = array_keys($sessionList);
3169
            if (in_array($session_id, $sessionList)) {
3170
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3171 View Code Duplication
                if (!empty($courseList)) {
3172
                    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...
3173
                        if (!in_array($course['id'], $courses)) {
3174
                            $personal_course_list[] = $course;
3175
                        }
3176
                    }
3177
                }
3178
            }
3179
        } else {
3180
            //check if user is general coach for this session
3181
            $sessionInfo = api_get_session_info($session_id);
3182
            if ($sessionInfo['id_coach'] == $user_id) {
3183
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3184 View Code Duplication
                if (!empty($courseList)) {
3185
                    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...
3186
                        if (!in_array($course['id'], $courses)) {
3187
                            $personal_course_list[] = $course;
3188
                        }
3189
                    }
3190
                }
3191
            }
3192
        }
3193
3194
        return $personal_course_list;
3195
    }
3196
3197
    /**
3198
     * Get user id from a username
3199
     * @param    string    $username
3200
     * @return    int        User ID (or false if not found)
3201
     */
3202
    public static function get_user_id_from_username($username)
3203
    {
3204
        if (empty($username)) {
3205
3206
            return false;
3207
        }
3208
        $username = trim($username);
3209
        $username = Database::escape_string($username);
3210
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
3211
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
3212
        $res = Database::query($sql);
3213
3214
        if ($res === false) {
3215
            return false;
3216
        }
3217
        if (Database::num_rows($res) !== 1) {
3218
            return false;
3219
        }
3220
        $row = Database::fetch_array($res);
3221
3222
        return $row['id'];
3223
    }
3224
3225
    /**
3226
     * Get the users files upload from his share_folder
3227
     * @param    string  $user_id   User ID
3228
     * @param   string  $course course directory
3229
     * @param   string  $resourcetype resourcetype: images, all
3230
     * @return    int        User ID (or false if not found)
3231
     */
3232
    public static function get_user_upload_files_by_course($user_id, $course, $resourcetype = 'all')
3233
    {
3234
        $return = '';
3235
        if (!empty($user_id) && !empty($course)) {
3236
            $user_id = intval($user_id);
3237
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3238
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3239
            $file_list = array();
3240
3241
            if (is_dir($path)) {
3242
                $handle = opendir($path);
3243
                while ($file = readdir($handle)) {
3244
                    if ($file == '.' || $file == '..' || $file == '.htaccess' || is_dir($path.$file)) {
3245
                        continue; // skip current/parent directory and .htaccess
3246
                    }
3247
                    $file_list[] = $file;
3248
                }
3249
                if (count($file_list) > 0) {
3250
                    $return = "<h4>$course</h4>";
3251
                    $return .= '<ul class="thumbnails">';
3252
                }
3253
                $extensionList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif'];
3254
                foreach ($file_list as $file) {
3255
                    if ($resourcetype == "all") {
3256
                        $return .= '<li><a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
3257
                    } elseif ($resourcetype == "images") {
3258
                        //get extension
3259
                        $ext = explode('.', $file);
3260
                        if (isset($ext[1]) && in_array($ext[1], $extensionList)) {
3261
                            $return .= '<li class="span2">
3262
                                            <a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
3263
                                                <img src="'.$web_path.urlencode($file).'" >
3264
                                            </a>
3265
                                        </li>';
3266
                        }
3267
                    }
3268
                }
3269
                if (count($file_list) > 0) {
3270
                    $return .= '</ul>';
3271
                }
3272
            }
3273
        }
3274
3275
        return $return;
3276
    }
3277
3278
    /**
3279
     * Gets the API key (or keys) and return them into an array
3280
     * @param   int     Optional user id (defaults to the result of api_get_user_id())
3281
     * @return  array   Non-indexed array containing the list of API keys for this user, or FALSE on error
3282
     */
3283
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
3284
    {
3285
        if ($user_id != strval(intval($user_id)))
3286
            return false;
3287
        if (empty($user_id)) {
3288
            $user_id = api_get_user_id();
3289
        }
3290
        if ($user_id === false)
3291
            return false;
3292
        $service_name = Database::escape_string($api_service);
3293
        if (is_string($service_name) === false) {
3294
            return false;
3295
        }
3296
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3297
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
3298
        $res = Database::query($sql);
3299
        if ($res === false)
3300
            return false; //error during query
3301
        $num = Database::num_rows($res);
3302
        if ($num == 0)
3303
            return false;
3304
        $list = array();
3305
        while ($row = Database::fetch_array($res)) {
3306
            $list[$row['id']] = $row['api_key'];
3307
        }
3308
        return $list;
3309
    }
3310
3311
    /**
3312
     * Adds a new API key to the users' account
3313
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
3314
     * @return  boolean True on success, false on failure
3315
     */
3316
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
3317
    {
3318
        if ($user_id != strval(intval($user_id)))
3319
            return false;
3320
        if (empty($user_id)) {
3321
            $user_id = api_get_user_id();
3322
        }
3323
        if ($user_id === false)
3324
            return false;
3325
        $service_name = Database::escape_string($api_service);
3326
        if (is_string($service_name) === false) {
3327
            return false;
3328
        }
3329
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3330
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
3331
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
3332
        $res = Database::query($sql);
3333
        if ($res === false)
3334
            return false; //error during query
3335
        $num = Database::insert_id();
3336
        return ($num == 0) ? false : $num;
3337
    }
3338
3339
    /**
3340
     * Deletes an API key from the user's account
3341
     * @param   int     API key's internal ID
3342
     * @return  boolean True on success, false on failure
3343
     */
3344
    public static function delete_api_key($key_id)
3345
    {
3346
        if ($key_id != strval(intval($key_id)))
3347
            return false;
3348
        if ($key_id === false)
3349
            return false;
3350
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3351
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
3352
        $res = Database::query($sql);
3353
        if ($res === false)
3354
            return false; //error during query
3355
        $num = Database::num_rows($res);
3356
        if ($num !== 1)
3357
            return false;
3358
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
3359
        $res = Database::query($sql);
3360
        if ($res === false)
3361
            return false; //error during query
3362
        return true;
3363
    }
3364
3365
    /**
3366
     * Regenerate an API key from the user's account
3367
     * @param   int     user ID (defaults to the results of api_get_user_id())
3368
     * @param   string  API key's internal ID
3369
     * @return  int        num
3370
     */
3371
    public static function update_api_key($user_id, $api_service)
3372
    {
3373
        if ($user_id != strval(intval($user_id)))
3374
            return false;
3375
        if ($user_id === false)
3376
            return false;
3377
        $service_name = Database::escape_string($api_service);
3378
        if (is_string($service_name) === false) {
3379
            return false;
3380
        }
3381
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3382
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3383
        $res = Database::query($sql);
3384
        $num = Database::num_rows($res);
3385
        if ($num == 1) {
3386
            $id_key = Database::fetch_array($res, 'ASSOC');
3387
            self::delete_api_key($id_key['id']);
3388
            $num = self::add_api_key($user_id, $api_service);
3389
        } elseif ($num == 0) {
3390
            $num = self::add_api_key($user_id, $api_service);
3391
        }
3392
        return $num;
3393
    }
3394
3395
    /**
3396
     * @param   int     user ID (defaults to the results of api_get_user_id())
3397
     * @param   string    API key's internal ID
3398
     * @return  int    row ID, or return false if not found
3399
     */
3400
    public static function get_api_key_id($user_id, $api_service)
3401
    {
3402
        if ($user_id != strval(intval($user_id)))
3403
            return false;
3404
        if ($user_id === false)
3405
            return false;
3406
        if (empty($api_service))
3407
            return false;
3408
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3409
        $api_service = Database::escape_string($api_service);
3410
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3411
        $res = Database::query($sql);
3412
        if (Database::num_rows($res) < 1) {
3413
            return false;
3414
        }
3415
        $row = Database::fetch_array($res, 'ASSOC');
3416
        return $row['id'];
3417
    }
3418
3419
    /**
3420
     * Checks if a user_id is platform admin
3421
     * @param   int user ID
3422
     * @return  boolean True if is admin, false otherwise
3423
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3424
     */
3425 View Code Duplication
    public static function is_admin($user_id)
3426
    {
3427
        if (empty($user_id) || $user_id != strval(intval($user_id))) {
3428
            return false;
3429
        }
3430
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3431
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3432
        $res = Database::query($sql);
3433
3434
        return Database::num_rows($res) === 1;
3435
    }
3436
3437
    /**
3438
     * Get the total count of users
3439
     * @param   int     Status of users to be counted
3440
     * @param   int     Access URL ID (optional)
3441
     * @return    mixed    Number of users or false on error
3442
     */
3443
    public static function get_number_of_users($status = 0, $access_url_id = 1)
3444
    {
3445
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3446
        $t_a = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3447
        $sql = "SELECT count(u.id) 
3448
                FROM $t_u u 
3449
                INNER JOIN $t_a url_user
3450
                ON (u.id = url_user.user_id)
3451
                WHERE url_user.access_url_id = $access_url_id                
3452
        ";
3453
        if (is_int($status) && $status > 0) {
3454
            $sql .= " AND u.status = $status ";
3455
        }
3456
        $res = Database::query($sql);
3457
        if (Database::num_rows($res) === 1) {
3458
            return (int) Database::result($res, 0, 0);
3459
        }
3460
        return false;
3461
    }
3462
3463
    /**
3464
     * @author Isaac flores <[email protected]>
3465
     * @param string The email administrator
3466
     * @param integer The user id
3467
     * @param string The message title
3468
     * @param string The content message
3469
     */
3470
    public static function send_message_in_outbox($email_administrator, $user_id, $title, $content)
3471
    {
3472
        $table_message = Database::get_main_table(TABLE_MESSAGE);
3473
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3474
        $title = api_utf8_decode($title);
3475
        $content = api_utf8_decode($content);
3476
        $email_administrator = Database::escape_string($email_administrator);
3477
        //message in inbox
3478
        $sql_message_outbox = 'SELECT id from '.$table_user.' WHERE email="'.$email_administrator.'" ';
3479
        //$num_row_query = Database::num_rows($sql_message_outbox);
3480
        $res_message_outbox = Database::query($sql_message_outbox);
3481
        $array_users_administrator = array();
3482
        while ($row_message_outbox = Database::fetch_array($res_message_outbox, 'ASSOC')) {
3483
            $array_users_administrator[] = $row_message_outbox['id'];
3484
        }
3485
        //allow to insert messages in outbox
3486
        for ($i = 0; $i < count($array_users_administrator); $i++) {
3487
            $sql_insert_outbox = "INSERT INTO $table_message(user_sender_id, user_receiver_id, msg_status, send_date, title, content ) ".
3488
                " VALUES (".
3489
                "'".(int) $user_id."', '".(int) ($array_users_administrator[$i])."', '4', '".api_get_utc_datetime()."','".Database::escape_string($title)."','".Database::escape_string($content)."'".
3490
                ")";
3491
            Database::query($sql_insert_outbox);
3492
        }
3493
    }
3494
3495
    /**
3496
     *
3497
     * Gets the tags of a specific field_id
3498
     * USER TAGS
3499
     *
3500
     * Instructions to create a new user tag by Julio Montoya <[email protected]>
3501
     *
3502
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible.
3503
     *    Called it "books" for example.
3504
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3505
     * 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
3506
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3507
     * 5. Test and enjoy.
3508
     *
3509
     * @param string $tag
3510
     * @param int $field_id field_id
3511
     * @param string $return_format how we are going to result value in array or in a string (json)
3512
     * @param $limit
3513
     *
3514
     * @return mixed
3515
     *
3516
     */
3517
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3518
    {
3519
        // database table definition
3520
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3521
        $field_id = intval($field_id);
3522
        $limit = intval($limit);
3523
        $tag = trim(Database::escape_string($tag));
3524
3525
        // all the information of the field
3526
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3527
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3528
        $result = Database::query($sql);
3529
        $return = array();
3530 View Code Duplication
        if (Database::num_rows($result) > 0) {
3531
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3532
                $return[] = array('id' => $row['tag'], 'text' => $row['tag']);
3533
            }
3534
        }
3535
        if ($return_format === 'json') {
3536
            $return = json_encode($return);
3537
        }
3538
3539
        return $return;
3540
    }
3541
3542
    /**
3543
     * @param int $field_id
3544
     * @param int $limit
3545
     *
3546
     * @return array
3547
     */
3548
    public static function get_top_tags($field_id, $limit = 100)
3549
    {
3550
        // database table definition
3551
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3552
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3553
        $field_id = intval($field_id);
3554
        $limit = intval($limit);
3555
        // all the information of the field
3556
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3557
                INNER JOIN $table_user_tag ut
3558
                ON(ut.id = uv.tag_id)
3559
                WHERE field_id = $field_id
3560
                GROUP BY tag_id
3561
                ORDER BY count DESC
3562
                LIMIT $limit";
3563
        $result = Database::query($sql);
3564
        $return = array();
3565
        if (Database::num_rows($result) > 0) {
3566
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3567
                $return[] = $row;
3568
            }
3569
        }
3570
        return $return;
3571
    }
3572
3573
    /**
3574
     * Get user's tags
3575
     * @param int $user_id
3576
     * @param int $field_id
3577
     *
3578
     * @return array
3579
     */
3580
    public static function get_user_tags($user_id, $field_id)
3581
    {
3582
        // database table definition
3583
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3584
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3585
        $field_id = intval($field_id);
3586
        $user_id = intval($user_id);
3587
3588
        // all the information of the field
3589
        $sql = "SELECT ut.id, tag, count
3590
                FROM $table_user_tag ut
3591
                INNER JOIN $table_user_tag_values uv
3592
                ON (uv.tag_id=ut.ID)
3593
                WHERE field_id = $field_id AND user_id = $user_id
3594
                ORDER BY tag";
3595
        $result = Database::query($sql);
3596
        $return = array();
3597 View Code Duplication
        if (Database::num_rows($result) > 0) {
3598
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3599
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3600
            }
3601
        }
3602
3603
        return $return;
3604
    }
3605
3606
    /**
3607
     * Get user's tags
3608
     * @param int $user_id
3609
     * @param int $field_id
3610
     * @param bool $show_links show links or not
3611
     *
3612
     * @return array
3613
     */
3614
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3615
    {
3616
        // database table definition
3617
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3618
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3619
        $field_id = intval($field_id);
3620
        $user_id = intval($user_id);
3621
3622
        // all the information of the field
3623
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3624
                INNER JOIN $table_user_tag_values uv
3625
                ON (uv.tag_id = ut.id)
3626
                WHERE field_id = $field_id AND user_id = $user_id
3627
                ORDER BY tag";
3628
3629
        $result = Database::query($sql);
3630
        $return = array();
3631 View Code Duplication
        if (Database::num_rows($result) > 0) {
3632
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3633
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3634
            }
3635
        }
3636
        $user_tags = $return;
3637
        $tag_tmp = array();
3638
        foreach ($user_tags as $tag) {
3639
            if ($show_links) {
3640
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.$tag['tag'].'</a>';
3641
            } else {
3642
                $tag_tmp[] = $tag['tag'];
3643
            }
3644
        }
3645
3646
        if (is_array($user_tags) && count($user_tags) > 0) {
3647
            $return = implode(', ', $tag_tmp);
3648
        } else {
3649
3650
            return '';
3651
        }
3652
3653
        return $return;
3654
    }
3655
3656
    /**
3657
     * Get the tag id
3658
     * @param int $tag
3659
     * @param int $field_id
3660
     * @return int returns 0 if fails otherwise the tag id
3661
     */
3662
    public static function get_tag_id($tag, $field_id)
3663
    {
3664
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3665
        $tag = Database::escape_string($tag);
3666
        $field_id = intval($field_id);
3667
        //with COLLATE latin1_bin to select query in a case sensitive mode
3668
        $sql = "SELECT id FROM $table_user_tag
3669
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3670
        $result = Database::query($sql);
3671
        if (Database::num_rows($result) > 0) {
3672
            $row = Database::fetch_array($result, 'ASSOC');
3673
3674
            return $row['id'];
3675
        } else {
3676
3677
            return 0;
3678
        }
3679
    }
3680
3681
    /**
3682
     * Get the tag id
3683
     * @param int $tag_id
3684
     * @param int $field_id
3685
     *
3686
     * @return int 0 if fails otherwise the tag id
3687
     */
3688 View Code Duplication
    public static function get_tag_id_from_id($tag_id, $field_id)
3689
    {
3690
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3691
        $tag_id = intval($tag_id);
3692
        $field_id = intval($field_id);
3693
        $sql = "SELECT id FROM $table_user_tag
3694
                WHERE id = '$tag_id' AND field_id = $field_id";
3695
        $result = Database::query($sql);
3696
        if (Database::num_rows($result) > 0) {
3697
            $row = Database::fetch_array($result, 'ASSOC');
3698
            return $row['id'];
3699
        } else {
3700
            return false;
3701
        }
3702
    }
3703
3704
    /**
3705
     * Adds a user-tag value
3706
     * @param mixed $tag
3707
     * @param int $user_id
3708
     * @param int $field_id field id of the tag
3709
     * @return bool
3710
     */
3711
    public static function add_tag($tag, $user_id, $field_id)
3712
    {
3713
        // database table definition
3714
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3715
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3716
        $tag = trim(Database::escape_string($tag));
3717
        $user_id = intval($user_id);
3718
        $field_id = intval($field_id);
3719
3720
        $tag_id = self::get_tag_id($tag, $field_id);
3721
3722
        /* IMPORTANT
3723
         *  @todo we don't create tags with numbers
3724
         *
3725
         */
3726
        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...
3727
            //the form is sending an id this means that the user select it from the list so it MUST exists
3728
            /* $new_tag_id = self::get_tag_id_from_id($tag,$field_id);
3729
              if ($new_tag_id !== false) {
3730
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3731
              $result = Database::query($sql);
3732
              $last_insert_id = $new_tag_id;
3733
              } else {
3734
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3735
              $result = Database::query($sql);
3736
              $last_insert_id = Database::insert_id();
3737
              } */
3738
        }
3739
3740
        //this is a new tag
3741
        if ($tag_id == 0) {
3742
            //the tag doesn't exist
3743
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3744
             Database::query($sql);
3745
            $last_insert_id = Database::insert_id();
3746
        } else {
3747
            //the tag exists we update it
3748
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3749
             Database::query($sql);
3750
            $last_insert_id = $tag_id;
3751
        }
3752
3753
        if (!empty($last_insert_id) && ($last_insert_id != 0)) {
3754
            //we insert the relationship user-tag
3755
            $sql = "SELECT tag_id FROM $table_user_tag_values
3756
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3757
            $result = Database::query($sql);
3758
            //if the relationship does not exist we create it
3759
            if (Database::num_rows($result) == 0) {
3760
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3761
                Database::query($sql);
3762
            }
3763
        }
3764
    }
3765
3766
    /**
3767
     * Deletes an user tag
3768
     * @param int $user_id
3769
     * @param int $field_id
3770
     *
3771
     */
3772
    public static function delete_user_tags($user_id, $field_id)
3773
    {
3774
        // database table definition
3775
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3776
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3777
        $tags = self::get_user_tags($user_id, $field_id);
3778
        if (is_array($tags) && count($tags) > 0) {
3779
            foreach ($tags as $key => $tag) {
3780
                if ($tag['count'] > '0') {
3781
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3782
                    Database::query($sql);
3783
                }
3784
                $sql = "DELETE FROM $table_user_tag_values
3785
                        WHERE user_id = $user_id AND tag_id = $key";
3786
                Database::query($sql);
3787
            }
3788
        }
3789
    }
3790
3791
    /**
3792
     * Process the tag list comes from the UserManager::update_extra_field_value() function
3793
     * @param array $tags the tag list that will be added
3794
     * @param int $user_id
3795
     * @param int $field_id
3796
     *
3797
     * @return bool
3798
     */
3799
    public static function process_tags($tags, $user_id, $field_id)
3800
    {
3801
        // We loop the tags and add it to the DB
3802
        if (is_array($tags)) {
3803
            foreach ($tags as $tag) {
3804
                self::add_tag($tag, $user_id, $field_id);
3805
            }
3806
        } else {
3807
            self::add_tag($tags, $user_id, $field_id);
3808
        }
3809
3810
        return true;
3811
    }
3812
3813
    /**
3814
     * Returns a list of all administrators
3815
     *
3816
     * @return array
3817
     */
3818
    public static function get_all_administrators()
3819
    {
3820
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3821
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3822
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3823
        $access_url_id = api_get_current_access_url_id();
3824
        if (api_get_multiple_access_url()) {
3825
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3826
                    FROM $tbl_url_rel_user as url
3827
                    INNER JOIN $table_admin as admin
3828
                    ON (admin.user_id=url.user_id)
3829
                    INNER JOIN $table_user u
3830
                    ON (u.id=admin.user_id)
3831
                    WHERE access_url_id ='".$access_url_id."'";
3832
        } else {
3833
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3834
                    FROM $table_admin as admin
3835
                    INNER JOIN $table_user u
3836
                    ON (u.id=admin.user_id)";
3837
        }
3838
        $result = Database::query($sql);
3839
        $return = array();
3840
        if (Database::num_rows($result) > 0) {
3841
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3842
                $return[$row['user_id']] = $row;
3843
            }
3844
        }
3845
3846
        return $return;
3847
    }
3848
3849
    /**
3850
     * Search an user (tags, first name, last name and email )
3851
     * @param string $tag
3852
     * @param int $field_id field id of the tag
3853
     * @param int $from where to start in the query
3854
     * @param int $number_of_items
3855
     * @param bool $getCount get count or not
3856
     * @return array
3857
     */
3858
    public static function get_all_user_tags(
3859
        $tag,
3860
        $field_id = 0,
3861
        $from = 0,
3862
        $number_of_items = 10,
3863
        $getCount = false
3864
    ) {
3865
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3866
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3867
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3868
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3869
3870
        $field_id = intval($field_id);
3871
        $from = intval($from);
3872
        $number_of_items = intval($number_of_items);
3873
3874
        $where_field = "";
3875
        $where_extra_fields = self::get_search_form_where_extra_fields();
3876
        if ($field_id != 0) {
3877
            $where_field = " field_id = $field_id AND ";
3878
        }
3879
3880
        // all the information of the field
3881
3882
        if ($getCount) {
3883
            $select = "SELECT count(DISTINCT u.id) count";
3884
        } else {
3885
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3886
        }
3887
3888
        $sql = " $select
3889
                FROM $user_table u
3890
                INNER JOIN $access_url_rel_user_table url_rel_user
3891
                ON (u.id = url_rel_user.user_id)
3892
                LEFT JOIN $table_user_tag_values uv
3893
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3894
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3895
                WHERE
3896
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3897
                    (
3898
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3899
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3900
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3901
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3902
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3903
                     )
3904
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3905
                     AND url_rel_user.access_url_id=".api_get_current_access_url_id();
3906
3907
        $keyword_active = true;
3908
        // only active users
3909
        if ($keyword_active) {
3910
            $sql .= " AND u.active='1'";
3911
        }
3912
        // avoid anonymous
3913
        $sql .= " AND u.status <> 6 ";
3914
        $sql .= " ORDER BY username";
3915
        $sql .= " LIMIT $from , $number_of_items";
3916
3917
        $result = Database::query($sql);
3918
        $return = array();
3919
3920
        if (Database::num_rows($result) > 0) {
3921
            if ($getCount) {
3922
                $row = Database::fetch_array($result, 'ASSOC');
3923
                return $row['count'];
3924
            }
3925
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3926
                if (isset($return[$row['id']]) &&
3927
                    !empty($return[$row['id']]['tag'])
3928
                ) {
3929
                    $url = Display::url(
3930
                        $row['tag'],
3931
                        api_get_path(WEB_PATH).'main/social/search.php?q='.$row['tag'],
3932
                        array('class' => 'tag')
3933
                    );
3934
                    $row['tag'] = $url;
3935
                }
3936
                $return[$row['id']] = $row;
3937
            }
3938
        }
3939
3940
        return $return;
3941
    }
3942
3943
    /**
3944
      * Get extra filtrable user fields (only type select)
3945
      * @return array
3946
      */
3947
    public static function get_extra_filtrable_fields()
3948
    {
3949
        $extraFieldList = self::get_extra_fields();
3950
3951
        $extraFiltrableFields = array();
3952 View Code Duplication
        if (is_array($extraFieldList)) {
3953
            foreach ($extraFieldList as $extraField) {
3954
                // If is enabled to filter and is a "<select>" field type
3955
                if ($extraField[8] == 1 && $extraField[2] == 4) {
3956
                    $extraFiltrableFields[] = array(
3957
                        'name' => $extraField[3],
3958
                        'variable' => $extraField[1],
3959
                        'data' => $extraField[9]
3960
                    );
3961
                }
3962
            }
3963
        }
3964
3965
        if (is_array($extraFiltrableFields) && count($extraFiltrableFields) > 0) {
3966
            return $extraFiltrableFields;
3967
        }
3968
    }
3969
3970
    /**
3971
      * Get extra where clauses for finding users based on extra filtrable user fields (type select)
3972
      * @return string With AND clauses based on user's ID which have the values to search in extra user fields
3973
      */
3974
    public static function get_search_form_where_extra_fields()
3975
    {
3976
        $useExtraFields = false;
3977
        $extraFields = self::get_extra_filtrable_fields();
3978
        $extraFieldResult = array();
3979 View Code Duplication
        if (is_array($extraFields) && count($extraFields) > 0) {
3980
            foreach ($extraFields as $extraField) {
3981
                $varName = 'field_'.$extraField['variable'];
3982
                if (self::is_extra_field_available($extraField['variable'])) {
3983
                    if (isset($_GET[$varName]) && $_GET[$varName] != '0') {
3984
                        $useExtraFields = true;
3985
                        $extraFieldResult[] = self::get_extra_user_data_by_value(
3986
                            $extraField['variable'],
3987
                            $_GET[$varName]
3988
                        );
3989
                    }
3990
                }
3991
            }
3992
        }
3993
3994
        if ($useExtraFields) {
3995
            $finalResult = array();
3996
            if (count($extraFieldResult) > 1) {
3997
                for ($i = 0; $i < count($extraFieldResult) - 1; $i++) {
3998
                if (is_array($extraFieldResult[$i]) && is_array($extraFieldResult[$i + 1])) {
3999
                        $finalResult = array_intersect($extraFieldResult[$i], $extraFieldResult[$i + 1]);
4000
                    }
4001
                }
4002
            } else {
4003
                $finalResult = $extraFieldResult[0];
4004
            }
4005
4006
            if (is_array($finalResult) && count($finalResult) > 0) {
4007
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
4008
            } else {
4009
                //no results
4010
                $whereFilter = " AND u.id  = -1 ";
4011
            }
4012
4013
            return $whereFilter;
4014
        }
4015
    }
4016
4017
    /**
4018
     * Show the search form
4019
     * @param string $query the value of the search box
4020
     * @return string HTML form
4021
     */
4022
    public static function get_search_form($query, $defaultParams = [])
4023
    {
4024
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
4025
        $form = new FormValidator(
4026
            'search_user',
4027
            'get',
4028
            api_get_path(WEB_PATH).'main/social/search.php',
4029
            '',
4030
            array(),
4031
            FormValidator::LAYOUT_HORIZONTAL
4032
        );
4033
4034
        $form->addText('q', get_lang('UsersGroups'), false, array(
4035
            "id" => "q"
4036
        ));
4037
        $options = array(
4038
            0 => get_lang('Select'),
4039
            1 => get_lang('User'),
4040
            2 => get_lang('Group'),
4041
        );
4042
        $form->addSelect(
4043
            'search_type',
4044
            get_lang('Type'),
4045
            $options,
4046
            array('onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type')
4047
        );
4048
4049
        // Extra fields
4050
4051
        $extraFields = self::get_extra_filtrable_fields();
4052
        $defaults = [];
4053
        if (is_array($extraFields) && count($extraFields) > 0) {
4054
            foreach ($extraFields as $extraField) {
4055
                $varName = 'field_'.$extraField['variable'];
4056
4057
                $options = [
4058
                    0 => get_lang('Select')
4059
                ];
4060
                foreach ($extraField['data'] as $option) {
4061
                    $checked = '';
4062
                    if (isset($_GET[$varName])) {
4063
                        if ($_GET[$varName] == $option[1]) {
4064
                            $defaults[$option[1]] = true;
4065
                        }
4066
                    }
4067
4068
                    $options[$option[1]] = $option[1];
4069
                }
4070
                $form->addSelect($varName, $extraField['name'], $options);
4071
            }
4072
        }
4073
4074
        $defaults['search_type'] = intval($searchType);
4075
        $defaults['q'] = api_htmlentities(Security::remove_XSS($query));
4076
4077
        if (!empty($defaultParams)) {
4078
            $defaults = array_merge($defaults, $defaultParams);
4079
        }
4080
        $form->setDefaults($defaults);
4081
4082
        $form->addButtonSearch(get_lang('Search'));
4083
4084
        $js = '<script>
4085
        extra_field_toogle();
4086
        function extra_field_toogle() {
4087
            if (jQuery("select[name=search_type]").val() != "1") { jQuery(".extra_field").hide(); } else { jQuery(".extra_field").show(); }
4088
        }
4089
        </script>';
4090
4091
        return $js.$form->returnForm();
4092
    }
4093
4094
    /**
4095
     * Shows the user menu
4096
     */
4097
    public static function show_menu()
4098
    {
4099
        echo '<div class="actions">';
4100
        echo '<a href="/main/auth/profile.php">'.Display::return_icon('profile.png').' '.get_lang('PersonalData').'</a>';
4101
        echo '<a href="/main/messages/inbox.php">'.Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
4102
        echo '<a href="/main/messages/outbox.php">'.Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
4103
        echo '<span style="float:right; padding-top:7px;">'.
4104
        '<a href="/main/auth/profile.php?show=1">'.Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
4105
        '</span>';
4106
        echo '</div>';
4107
    }
4108
4109
    /**
4110
     * Allow to register contact to social network
4111
     * @param int $friend_id user friend id
4112
     * @param int $my_user_id user id
4113
     * @param int $relation_type relation between users see constants definition
4114
     */
4115
    public static function relate_users($friend_id, $my_user_id, $relation_type)
4116
    {
4117
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4118
4119
        $friend_id = intval($friend_id);
4120
        $my_user_id = intval($my_user_id);
4121
        $relation_type = intval($relation_type);
4122
4123
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4124
                WHERE
4125
                    friend_user_id='.$friend_id.' AND
4126
                    user_id='.$my_user_id.' AND
4127
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
4128
        $result = Database::query($sql);
4129
        $row = Database::fetch_array($result, 'ASSOC');
4130
        $current_date = api_get_utc_datetime();
4131
4132
        if ($row['count'] == 0) {
4133
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4134
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4135
            Database::query($sql);
4136
            return true;
4137
        }
4138
4139
        $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
4140
                WHERE
4141
                    friend_user_id='.$friend_id.' AND
4142
                    user_id='.$my_user_id.' AND
4143
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
4144
        $result = Database::query($sql);
4145
        $row = Database::fetch_array($result, 'ASSOC');
4146
4147
        if ($row['count'] == 1) {
4148
            //only for the case of a RRHH
4149
            if ($row['relation_type'] != $relation_type && $relation_type == USER_RELATION_TYPE_RRHH) {
4150
                $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4151
                        VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4152
            } else {
4153
                $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
4154
                        WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
4155
            }
4156
            Database::query($sql);
4157
4158
            return true;
4159
        }
4160
4161
        return false;
4162
    }
4163
4164
    /**
4165
     * Deletes a contact
4166
     * @param int user friend id
4167
     * @param bool true will delete ALL friends relationship from $friend_id
4168
     * @author isaac flores paz <[email protected]>
4169
     * @author Julio Montoya <[email protected]> Cleaning code
4170
     */
4171
    public static function remove_user_rel_user($friend_id, $real_removed = false, $with_status_condition = '')
4172
    {
4173
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4174
        $tbl_my_message = Database::get_main_table(TABLE_MESSAGE);
4175
        $friend_id = intval($friend_id);
4176
4177
        if ($real_removed) {
4178
            $extra_condition = '';
4179
            if ($with_status_condition != '') {
4180
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
4181
            }
4182
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4183
                    WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND friend_user_id='.$friend_id.' '.$extra_condition;
4184
            Database::query($sql);
4185
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4186
                   WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND user_id='.$friend_id.' '.$extra_condition;
4187
            Database::query($sql);
4188
        } else {
4189
            $user_id = api_get_user_id();
4190
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4191
                    WHERE
4192
                        user_id='.$user_id.' AND
4193
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
4194
                        friend_user_id='.$friend_id;
4195
            $result = Database::query($sql);
4196
            $row = Database::fetch_array($result, 'ASSOC');
4197
            if ($row['count'] == 1) {
4198
                //Delete user rel user
4199
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
4200
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
4201
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4202
                          WHERE user_receiver_id='.$user_id.' AND user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
4203
                //Delete user
4204
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
4205
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
4206
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4207
                           WHERE user_receiver_id='.$friend_id.' AND user_sender_id='.$user_id.' AND update_date="0000-00-00 00:00:00" ';
4208
                Database::query($sql_i);
4209
                Database::query($sql_j);
4210
                Database::query($sql_ij);
4211
                Database::query($sql_ji);
4212
            }
4213
        }
4214
    }
4215
4216
    /**
4217
     * @param int $userId
4218
     * @return array
4219
     */
4220
    public static function getDrhListFromUser($userId)
4221
    {
4222
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4223
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4224
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4225
        $userId = intval($userId);
4226
4227
        $orderBy = null;
4228
        if (api_is_western_name_order()) {
4229
            $orderBy .= " ORDER BY firstname, lastname ";
4230
        } else {
4231
            $orderBy .= " ORDER BY lastname, firstname ";
4232
        }
4233
4234
        $sql = "SELECT u.id, username, u.firstname, u.lastname
4235
                FROM $tblUser u
4236
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
4237
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
4238
                WHERE
4239
                    access_url_id = ".api_get_current_access_url_id()." AND
4240
                    uru.user_id = '$userId' AND
4241
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4242
                $orderBy
4243
                ";
4244
        $result = Database::query($sql);
4245
4246
        return Database::store_result($result);
4247
    }
4248
4249
    /**
4250
     * get users followed by human resource manager
4251
     * @param int $userId
4252
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
4253
     * @param bool $getOnlyUserId
4254
     * @param bool $getSql
4255
     * @param bool $getCount
4256
     * @param int $from
4257
     * @param int $numberItems
4258
     * @param int $column
4259
     * @param string $direction
4260
     * @param int $active
4261
     * @param string $lastConnectionDate
4262
     * @return array     users
4263
     */
4264 View Code Duplication
    public static function get_users_followed_by_drh(
4265
        $userId,
4266
        $userStatus = 0,
4267
        $getOnlyUserId = false,
4268
        $getSql = false,
4269
        $getCount = false,
4270
        $from = null,
4271
        $numberItems = null,
4272
        $column = null,
4273
        $direction = null,
4274
        $active = null,
4275
        $lastConnectionDate = null
4276
    ) {
4277
        return self::getUsersFollowedByUser(
4278
            $userId,
4279
            $userStatus,
4280
            $getOnlyUserId,
4281
            $getSql,
4282
            $getCount,
4283
            $from,
4284
            $numberItems,
4285
            $column,
4286
            $direction,
4287
            $active,
4288
            $lastConnectionDate,
4289
            DRH
4290
        );
4291
    }
4292
4293
    /**
4294
    * Get users followed by human resource manager
4295
    * @param int $userId
4296
    * @param int  $userStatus Filter users by status (STUDENT, COURSEMANAGER, etc)
4297
    * @param bool $getOnlyUserId
4298
    * @param bool $getSql
4299
    * @param bool $getCount
4300
    * @param int $from
4301
    * @param int $numberItems
4302
    * @param int $column
4303
    * @param string $direction
4304
    * @param int $active
4305
    * @param string $lastConnectionDate
4306
    * @param int $status the function is called by who? COURSEMANAGER, DRH?
4307
    * @param string $keyword
4308
     *
4309
    * @return array user list
4310
    */
4311
    public static function getUsersFollowedByUser(
4312
        $userId,
4313
        $userStatus = null,
4314
        $getOnlyUserId = false,
4315
        $getSql = false,
4316
        $getCount = false,
4317
        $from = null,
4318
        $numberItems = null,
4319
        $column = null,
4320
        $direction = null,
4321
        $active = null,
4322
        $lastConnectionDate = null,
4323
        $status = null,
4324
        $keyword = null
4325
    ) {
4326
        // Database Table Definitions
4327
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4328
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4329
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4330
4331
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4332
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4333
4334
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4335
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4336
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4337
4338
        $userId = intval($userId);
4339
4340
        $limitCondition = '';
4341
4342 View Code Duplication
        if (isset($from) && isset($numberItems)) {
4343
            $from = intval($from);
4344
            $numberItems = intval($numberItems);
4345
            $limitCondition = "LIMIT $from, $numberItems";
4346
        }
4347
4348
        $column = Database::escape_string($column);
4349
        $direction = in_array(strtolower($direction), array('asc', 'desc')) ? $direction : null;
4350
4351
        $userConditions = '';
4352
        if (!empty($userStatus)) {
4353
            $userConditions .= ' AND u.status = '.intval($userStatus);
4354
        }
4355
4356
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
4357
        if ($getOnlyUserId) {
4358
            $select = " SELECT DISTINCT u.id user_id";
4359
        }
4360
4361
        $masterSelect = "SELECT DISTINCT * FROM ";
4362
4363
        if ($getCount) {
4364
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
4365
            $select = " SELECT DISTINCT(u.id) user_id";
4366
        }
4367
4368
        if (!is_null($active)) {
4369
            $active = intval($active);
4370
            $userConditions .= " AND u.active = $active ";
4371
        }
4372
4373 View Code Duplication
        if (!empty($keyword)) {
4374
            $keyword = Database::escape_string($keyword);
4375
            $userConditions .= " AND (
4376
                u.username LIKE '%$keyword%' OR
4377
                u.firstname LIKE '%$keyword%' OR
4378
                u.lastname LIKE '%$keyword%' OR
4379
                u.official_code LIKE '%$keyword%' OR
4380
                u.email LIKE '%$keyword%'
4381
            )";
4382
        }
4383
4384
        if (!empty($lastConnectionDate)) {
4385
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
4386
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
4387
        }
4388
4389
        $courseConditions = null;
4390
        $sessionConditionsCoach = null;
4391
        $sessionConditionsTeacher = null;
4392
        $drhConditions = null;
4393
        $teacherSelect = null;
4394
4395
        switch ($status) {
4396
            case DRH:
4397
                $drhConditions .= " AND
4398
                    friend_user_id = '$userId' AND
4399
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4400
                ";
4401
                break;
4402
            case COURSEMANAGER:
4403
                $drhConditions .= " AND
4404
                    friend_user_id = '$userId' AND
4405
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4406
                ";
4407
4408
                $sessionConditionsCoach .= " AND
4409
                    (s.id_coach = '$userId')
4410
                ";
4411
4412
                $sessionConditionsTeacher .= " AND
4413
                    (scu.status = 2 AND scu.user_id = '$userId')
4414
                ";
4415
4416
                $teacherSelect =
4417
                "UNION ALL (
4418
                        $select
4419
                        FROM $tbl_user u
4420
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4421
                        WHERE
4422
                            (
4423
                                sru.session_id IN (
4424
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4425
                                    $tbl_session_rel_access_url session_rel_access_rel_user
4426
                                    ON session_rel_access_rel_user.session_id = s.id
4427
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4428
                                    $sessionConditionsCoach                                  
4429
                                ) OR sru.session_id IN (
4430
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4431
                                    INNER JOIN $tbl_session_rel_access_url url
4432
                                    ON (url.session_id = s.id)
4433
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4434
                                    ON (scu.session_id = s.id)
4435
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4436
                                    $sessionConditionsTeacher
4437
                                )
4438
                            )                            
4439
                            $userConditions
4440
                    )
4441
                    UNION ALL(
4442
                        $select
4443
                        FROM $tbl_user u
4444
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4445
                        WHERE cu.c_id IN (
4446
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4447
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4448
                        )
4449
                        $userConditions
4450
                    )"
4451
                ;
4452
                break;
4453
            case STUDENT_BOSS:
4454
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4455
                break;
4456
        }
4457
4458
        $join = null;
4459
        $sql = " $masterSelect
4460
                (
4461
                    (
4462
                        $select
4463
                        FROM $tbl_user u
4464
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4465
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4466
                        $join
4467
                        WHERE
4468
                            access_url_id = ".api_get_current_access_url_id()."
4469
                            $drhConditions
4470
                            $userConditions
4471
                    )
4472
                    $teacherSelect
4473
4474
                ) as t1";
4475
4476
        if ($getSql) {
4477
            return $sql;
4478
        }
4479 View Code Duplication
        if ($getCount) {
4480
            $result = Database::query($sql);
4481
            $row = Database::fetch_array($result);
4482
            return $row['count'];
4483
        }
4484
4485
        $orderBy = null;
4486
        if ($getOnlyUserId == false) {
4487
            if (api_is_western_name_order()) {
4488
                $orderBy .= " ORDER BY firstname, lastname ";
4489
            } else {
4490
                $orderBy .= " ORDER BY lastname, firstname ";
4491
            }
4492
4493 View Code Duplication
            if (!empty($column) && !empty($direction)) {
4494
                // Fixing order due the UNIONs
4495
                $column = str_replace('u.', '', $column);
4496
                $orderBy = " ORDER BY $column $direction ";
4497
            }
4498
        }
4499
4500
        $sql .= $orderBy;
4501
        $sql .= $limitCondition;
4502
4503
        $result = Database::query($sql);
4504
        $users = array();
4505
        if (Database::num_rows($result) > 0) {
4506
4507
            while ($row = Database::fetch_array($result)) {
4508
                $users[$row['user_id']] = $row;
4509
            }
4510
        }
4511
4512
        return $users;
4513
    }
4514
4515
    /**
4516
     * Subscribes users to human resource manager (Dashboard feature)
4517
     * @param   int    $hr_dept_id
4518
     * @param   array   $users_id
4519
     * @param   int     affected rows
4520
     * */
4521
    public static function subscribeUsersToHRManager($hr_dept_id, $users_id)
4522
    {
4523
        return self::subscribeUsersToUser($hr_dept_id, $users_id, USER_RELATION_TYPE_RRHH);
4524
    }
4525
4526
    /**
4527
     * Add subscribed users to a user by relation type
4528
     * @param int $userId The user id
4529
     * @param array $subscribedUsersId The id of suscribed users
4530
     * @param string $relationType The relation type
4531
     * @param bool $deleteUsersBeforeInsert
4532
     */
4533
    public static function subscribeUsersToUser($userId, $subscribedUsersId, $relationType, $deleteUsersBeforeInsert = false)
4534
    {
4535
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4536
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4537
4538
        $userId = intval($userId);
4539
        $relationType = intval($relationType);
4540
        $affectedRows = 0;
4541
4542
        if (api_get_multiple_access_url()) {
4543
            // Deleting assigned users to hrm_id
4544
            $sql = "SELECT s.user_id FROM $userRelUserTable s 
4545
                    INNER JOIN $userRelAccessUrlTable a ON (a.user_id = s.user_id) 
4546
                    WHERE 
4547
                        friend_user_id = $userId AND 
4548
                        relation_type = $relationType AND 
4549
                        access_url_id = ".api_get_current_access_url_id();
4550
        } else {
4551
            $sql = "SELECT user_id FROM $userRelUserTable 
4552
                    WHERE friend_user_id = $userId 
4553
                    AND relation_type = $relationType";
4554
        }
4555
        $result = Database::query($sql);
4556
4557 View Code Duplication
        if (Database::num_rows($result) > 0) {
4558
            while ($row = Database::fetch_array($result)) {
4559
                $sql = "DELETE FROM $userRelUserTable 
4560
                        WHERE 
4561
                          user_id = {$row['user_id']} AND 
4562
                          friend_user_id = $userId AND 
4563
                          relation_type = $relationType";
4564
                Database::query($sql);
4565
            }
4566
        }
4567
4568
        if ($deleteUsersBeforeInsert) {
4569
            $sql = "DELETE FROM $userRelUserTable 
4570
                    WHERE 
4571
                        user_id = $userId AND
4572
                        relation_type = $relationType";
4573
            Database::query($sql);
4574
        }
4575
4576
        // Inserting new user list
4577
        if (is_array($subscribedUsersId)) {
4578
            foreach ($subscribedUsersId as $subscribedUserId) {
4579
                $subscribedUserId = intval($subscribedUserId);
4580
4581
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4582
                        VALUES ($subscribedUserId, $userId, $relationType)";
4583
4584
                $result = Database::query($sql);
4585
                $affectedRows = Database::affected_rows($result);
4586
            }
4587
        }
4588
4589
        return $affectedRows;
4590
    }
4591
4592
    /**
4593
     * This function check if an user is followed by human resources manager
4594
     * @param     int     $user_id
4595
     * @param    int      $hr_dept_id  Human resources manager
4596
     * @return    bool
4597
     */
4598
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4599
    {
4600
        // Database table and variables Definitions
4601
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4602
        $user_id = intval($user_id);
4603
        $hr_dept_id = intval($hr_dept_id);
4604
        $result = false;
4605
4606
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4607
                WHERE
4608
                    user_id = $user_id AND
4609
                    friend_user_id = $hr_dept_id AND
4610
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4611
        $rs = Database::query($sql);
4612
        if (Database::num_rows($rs) > 0) {
4613
            $result = true;
4614
        }
4615
        return $result;
4616
    }
4617
4618
    /**
4619
     * get user id of teacher or session administrator
4620
     * @param array $courseInfo
4621
     *
4622
     * @return int The user id
4623
     */
4624
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4625
    {
4626
        $session = api_get_session_id();
4627
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4628
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4629
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4630
        $courseId = $courseInfo['real_id'];
4631
4632
        if ($session == 0 || is_null($session)) {
4633
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4634
                    INNER JOIN '.$table_course_user.' ru
4635
                    ON ru.user_id = u.id
4636
                    WHERE
4637
                        ru.status = 1 AND
4638
                        ru.c_id = "'.$courseId.'" ';
4639
            $rs = Database::query($sql);
4640
            $num_rows = Database::num_rows($rs);
4641
            if ($num_rows == 1) {
4642
                $row = Database::fetch_array($rs);
4643
                return $row['uid'];
4644
            } else {
4645
                $my_num_rows = $num_rows;
4646
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4647
4648
                return $my_user_id;
4649
            }
4650
        } elseif ($session > 0) {
4651
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4652
                    INNER JOIN '.$table_session_course_user.' sru
4653
                    ON sru.user_id=u.id
4654
                    WHERE
4655
                        sru.c_id="'.$courseId.'" AND
4656
                        sru.status=2';
4657
            $rs = Database::query($sql);
4658
            $row = Database::fetch_array($rs);
4659
4660
            return $row['uid'];
4661
        }
4662
    }
4663
4664
    /**
4665
     * Determines if a user is a gradebook certified
4666
     * @param int $cat_id The category id of gradebook
4667
     * @param int $user_id The user id
4668
     * @return boolean
4669
     */
4670 View Code Duplication
    public static function is_user_certified($cat_id, $user_id)
4671
    {
4672
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4673
        $sql = 'SELECT path_certificate FROM '.$table_certificate.'
4674
                WHERE
4675
                    cat_id="'.intval($cat_id).'" AND
4676
                    user_id="'.intval($user_id).'"';
4677
        $rs = Database::query($sql);
4678
        $row = Database::fetch_array($rs);
4679
        if ($row['path_certificate'] == '' || is_null($row['path_certificate'])) {
4680
            return false;
4681
        } else {
4682
            return true;
4683
        }
4684
    }
4685
4686
    /**
4687
     * Gets the info about a gradebook certificate for a user by course
4688
     * @param int $courseId course id
4689
     * @param int $user_id The user id
4690
     * @return array  if there is not information return false
4691
     */
4692
    public static function getInfoGradeBookCertificate($courseId, $user_id)
4693
    {
4694
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4695
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4696
        $session_id = api_get_session_id();
4697
4698
        if (empty($session_id)) {
4699
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4700
        } else {
4701
            $session_condition = " AND session_id = $session_id";
4702
        }
4703
4704
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.' 
4705
                WHERE cat_id = (
4706
                    SELECT id FROM '.$tbl_grade_category.'
4707
                    WHERE
4708
                        c_id = "'.Database::escape_string($courseId).'" '.$session_condition.' 
4709
                    LIMIT 1
4710
                 ) 
4711
                 AND user_id='.intval($user_id);
4712
4713
        $rs = Database::query($sql);
4714
        if (Database::num_rows($rs) > 0) {
4715
            $row = Database::fetch_array($rs, 'ASSOC');
4716
            $score = $row['score_certificate'];
4717
            $category_id = $row['cat_id'];
4718
            $cat = Category::load($category_id);
4719
            $displayscore = ScoreDisplay::instance();
4720
            if (isset($cat) && $displayscore->is_custom()) {
4721
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()), SCORE_DIV_PERCENT_WITH_CUSTOM);
4722
            } else {
4723
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()));
4724
            }
4725
            $row['grade'] = $grade;
4726
4727
            return $row;
4728
        }
4729
4730
        return false;
4731
    }
4732
4733
    /**
4734
     * Gets the user path of user certificated
4735
     * @param int The user id
4736
     * @return array  containing path_certificate and cat_id
4737
     */
4738
    public static function get_user_path_certificate($user_id)
4739
    {
4740
        $my_certificate = array();
4741
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4742
        $table_gradebook_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4743
4744
        $session_id = api_get_session_id();
4745
        $user_id = intval($user_id);
4746 View Code Duplication
        if ($session_id == 0 || is_null($session_id)) {
4747
            $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
4748
        } elseif ($session_id > 0) {
4749
            $sql_session = 'AND session_id='.intval($session_id);
4750
        } else {
4751
            $sql_session = '';
4752
        }
4753
        $sql = "SELECT tc.path_certificate,tc.cat_id,tgc.course_code,tgc.name
4754
                FROM $table_certificate tc, $table_gradebook_category tgc
4755
                WHERE tgc.id = tc.cat_id AND tc.user_id = $user_id
4756
                ORDER BY tc.date_certificate DESC 
4757
                LIMIT 5";
4758
4759
        $rs = Database::query($sql);
4760
        while ($row = Database::fetch_array($rs)) {
4761
            $my_certificate[] = $row;
4762
        }
4763
        return $my_certificate;
4764
    }
4765
4766
    /**
4767
     * This function check if the user is a coach inside session course
4768
     * @param  int  $user_id    User id
4769
     * @param  int  $courseId
4770
     * @param  int  $session_id
4771
     * @return bool    True if the user is a coach
4772
     *
4773
     */
4774 View Code Duplication
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4775
    {
4776
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4777
        // Protect data
4778
        $user_id = intval($user_id);
4779
        $courseId = intval($courseId);
4780
        $session_id = intval($session_id);
4781
        $result = false;
4782
4783
        $sql = "SELECT session_id FROM $tbl_session_course_rel_user
4784
                WHERE
4785
                  session_id = $session_id AND
4786
                  c_id = $courseId AND
4787
                  user_id = $user_id AND
4788
                  status = 2 ";
4789
        $res = Database::query($sql);
4790
4791
        if (Database::num_rows($res) > 0) {
4792
            $result = true;
4793
        }
4794
        return $result;
4795
    }
4796
4797
    /**
4798
     * This function returns an icon path that represents the favicon of the website of which the url given.
4799
     * Defaults to the current Chamilo favicon
4800
     * @param    string    $url1 URL of website where to look for favicon.ico
4801
     * @param    string    $url2 Optional second URL of website where to look for favicon.ico
4802
     * @return    string    Path of icon to load
4803
     */
4804
    public static function get_favicon_from_url($url1, $url2 = null)
4805
    {
4806
        $icon_link = '';
4807
        $url = $url1;
4808
        if (empty($url1)) {
4809
            $url = $url2;
4810
            if (empty($url)) {
4811
                $url = api_get_access_url(api_get_current_access_url_id());
4812
                $url = $url[0];
4813
            }
4814
        }
4815
        if (!empty($url)) {
4816
            $pieces = parse_url($url);
4817
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
4818
        }
4819
        return $icon_link;
4820
    }
4821
4822
    /**
4823
     *
4824
     * @param int   student id
4825
     * @param int   years
4826
     * @param bool  show warning_message
4827
     * @param bool  return_timestamp
4828
     */
4829
    public static function delete_inactive_student($student_id, $years = 2, $warning_message = false, $return_timestamp = false)
4830
    {
4831
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
4832
        $sql = 'SELECT login_date FROM '.$tbl_track_login.'
4833
                WHERE login_user_id = '.intval($student_id).'
4834
                ORDER BY login_date DESC LIMIT 0,1';
4835
        if (empty($years)) {
4836
            $years = 1;
4837
        }
4838
        $inactive_time = $years * 31536000; //1 year
4839
        $rs = Database::query($sql);
4840
        if (Database::num_rows($rs) > 0) {
4841
            if ($last_login_date = Database::result($rs, 0, 0)) {
4842
                $last_login_date = api_get_local_time($last_login_date, null, date_default_timezone_get());
4843
                if ($return_timestamp) {
4844
                    return api_strtotime($last_login_date);
4845
                } else {
4846
                    if (!$warning_message) {
4847
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
4848
                    } else {
4849
                        $timestamp = api_strtotime($last_login_date);
4850
                        $currentTimestamp = time();
4851
4852
                        //If the last connection is > than 7 days, the text is red
4853
                        //345600 = 7 days in seconds 63072000= 2 ans
4854
                        // if ($currentTimestamp - $timestamp > 184590 )
4855
                        if ($currentTimestamp - $timestamp > $inactive_time && self::delete_user($student_id)) {
4856
                            echo Display::return_message(get_lang('UserDeleted'));
4857
                            echo '<p>', 'id', $student_id, ':', $last_login_date, '</p>';
4858
                        }
4859
                    }
4860
                }
4861
            }
4862
        }
4863
        return false;
4864
    }
4865
4866
    /**
4867
     * @return array
4868
     */
4869
    public static function get_user_field_types()
4870
    {
4871
        $types = array();
4872
        $types[self::USER_FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
4873
        $types[self::USER_FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
4874
        $types[self::USER_FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
4875
        $types[self::USER_FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
4876
        $types[self::USER_FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
4877
        $types[self::USER_FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
4878
        $types[self::USER_FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
4879
        $types[self::USER_FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
4880
        $types[self::USER_FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
4881
        $types[self::USER_FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
4882
        $types[self::USER_FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
4883
        $types[self::USER_FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
4884
        $types[self::USER_FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
4885
        $types[self::USER_FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
4886
4887
        return $types;
4888
    }
4889
4890
    /**
4891
     * @param User $user
4892
     */
4893
    public static function add_user_as_admin(User $user)
4894
    {
4895
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
4896
        if ($user) {
4897
            $userId = $user->getId();
4898
4899
            if (!self::is_admin($userId)) {
4900
                $sql = "INSERT INTO $table_admin SET user_id = $userId";
4901
                Database::query($sql);
4902
            }
4903
4904
            $user->addRole('ROLE_SUPER_ADMIN');
4905
            self::getManager()->updateUser($user, true);
4906
        }
4907
    }
4908
4909
    /**
4910
     * @param int $userId
4911
     */
4912 View Code Duplication
    public static function remove_user_admin($userId)
4913
    {
4914
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
4915
        $userId = intval($userId);
4916
        if (self::is_admin($userId)) {
4917
            $sql = "DELETE FROM $table_admin WHERE user_id = $userId";
4918
            Database::query($sql);
4919
        }
4920
    }
4921
4922
    /**
4923
     * @param string $from
4924
     * @param string $to
4925
     */
4926
    public static function update_all_user_languages($from, $to)
4927
    {
4928
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4929
        $from = Database::escape_string($from);
4930
        $to = Database::escape_string($to);
4931
4932
        if (!empty($to) && !empty($from)) {
4933
            $sql = "UPDATE $table_user SET language = '$to'
4934
                    WHERE language = '$from'";
4935
            Database::query($sql);
4936
        }
4937
    }
4938
4939
    /**
4940
     * Subscribe boss to students
4941
     *
4942
     * @param int $bossId The boss id
4943
     * @param array $usersId The users array
4944
     * @return int Affected rows
4945
     */
4946
    public static function subscribeBossToUsers($bossId, $usersId)
4947
    {
4948
        return self::subscribeUsersToUser($bossId, $usersId, USER_RELATION_TYPE_BOSS);
4949
    }
4950
4951
    /**
4952
     * Subscribe boss to students
4953
     *
4954
     * @param int $studentId
4955
     * @param array $bossList
4956
     * @return int Affected rows
4957
     */
4958
    public static function subscribeUserToBossList($studentId, $bossList)
4959
    {
4960
        if ($bossList) {
4961
            $studentId = (int) $studentId;
4962
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4963
            $sql = "DELETE FROM $userRelUserTable 
4964
                    WHERE user_id = $studentId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4965
            Database::query($sql);
4966
4967
            foreach ($bossList as $bossId) {
4968
                $bossId = (int) $bossId;
4969
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4970
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
4971
4972
                Database::query($sql);
4973
            }
4974
        }
4975
    }
4976
4977
    /**
4978
     * Get users followed by student boss
4979
     * @param int $userId
4980
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
4981
     * @param bool $getOnlyUserId
4982
     * @param bool $getSql
4983
     * @param bool $getCount
4984
     * @param int $from
4985
     * @param int $numberItems
4986
     * @param int $column
4987
     * @param string $direction
4988
     * @param int $active
4989
     * @param string $lastConnectionDate
4990
     * @return array     users
4991
     */
4992 View Code Duplication
    public static function getUsersFollowedByStudentBoss(
4993
        $userId,
4994
        $userStatus = 0,
4995
        $getOnlyUserId = false,
4996
        $getSql = false,
4997
        $getCount = false,
4998
        $from = null,
4999
        $numberItems = null,
5000
        $column = null,
5001
        $direction = null,
5002
        $active = null,
5003
        $lastConnectionDate = null
5004
    ) {
5005
        return self::getUsersFollowedByUser(
5006
            $userId,
5007
            $userStatus,
5008
            $getOnlyUserId,
5009
            $getSql,
5010
            $getCount,
5011
            $from,
5012
            $numberItems,
5013
            $column,
5014
            $direction,
5015
            $active,
5016
            $lastConnectionDate,
5017
            STUDENT_BOSS
5018
        );
5019
    }
5020
5021
    /**
5022
     * Get the teacher (users with COURSEMANGER status) list
5023
     * @return array The list
5024
     */
5025
    public static function getTeachersList()
5026
    {
5027
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5028
5029
        $resultData = Database::select('user_id, lastname, firstname, username', $userTable, array(
5030
            'where' => array(
5031
                'status = ?' => COURSEMANAGER
5032
            )
5033
        ));
5034
5035
        foreach ($resultData as &$teacherData) {
5036
            $teacherData['completeName'] = api_get_person_name($teacherData['firstname'], $teacherData['lastname']);
5037
        }
5038
5039
        return $resultData;
5040
    }
5041
5042
    /**
5043
     * @return array
5044
     */
5045 View Code Duplication
    public static function getOfficialCodeGrouped()
5046
    {
5047
        $user = Database::get_main_table(TABLE_MAIN_USER);
5048
        $sql = "SELECT DISTINCT official_code
5049
                FROM $user
5050
                GROUP BY official_code";
5051
        $result = Database::query($sql);
5052
5053
        $values = Database::store_result($result, 'ASSOC');
5054
5055
        $result = array();
5056
        foreach ($values as $value) {
5057
            $result[$value['official_code']] = $value['official_code'];
5058
        }
5059
        return $result;
5060
    }
5061
5062
    /**
5063
     * @param string $officialCode
5064
     * @return array
5065
     */
5066
    public static function getUsersByOfficialCode($officialCode)
5067
    {
5068
        $user = Database::get_main_table(TABLE_MAIN_USER);
5069
        $officialCode = Database::escape_string($officialCode);
5070
5071
        $sql = "SELECT DISTINCT id
5072
                FROM $user
5073
                WHERE official_code = '$officialCode'
5074
                ";
5075
        $result = Database::query($sql);
5076
5077
        $users = array();
5078
        while ($row = Database::fetch_array($result)) {
5079
            $users[] = $row['id'];
5080
        }
5081
        return $users;
5082
    }
5083
5084
    /**
5085
     * Calc the expended time (in seconds) by a user in a course
5086
     * @param int $userId The user id
5087
     * @param int $courseId The course id
5088
     * @param int $sessionId Optional. The session id
5089
     * @param string $from Optional. From date
5090
     * @param string $until Optional. Until date
5091
     * @return int The time
5092
     */
5093
    public static function getTimeSpentInCourses($userId, $courseId, $sessionId = 0, $from = '', $until = '')
5094
    {
5095
        $userId = intval($userId);
5096
        $sessionId = intval($sessionId);
5097
5098
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5099
5100
        $whereConditions = array(
5101
            'user_id = ? ' => $userId,
5102
            'AND c_id = ? ' => $courseId,
5103
            'AND session_id = ? ' => $sessionId
5104
        );
5105
5106 View Code Duplication
        if (!empty($from) && !empty($until)) {
5107
            $whereConditions["AND (login_course_date >= '?' "] = $from;
5108
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
5109
        }
5110
5111
        $trackResult = Database::select(
5112
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
5113
            $trackCourseAccessTable,
5114
            array(
5115
                'where' => $whereConditions
5116
            ), 'first'
5117
        );
5118
5119
        if ($trackResult != false) {
5120
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5121
        }
5122
5123
        return 0;
5124
    }
5125
5126
    /**
5127
     * Get the boss user ID from a followed user id
5128
     * @param $userId
5129
     * @return bool
5130
     */
5131 View Code Duplication
    public static function getFirstStudentBoss($userId)
5132
    {
5133
        $userId = intval($userId);
5134
        if ($userId > 0) {
5135
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5136
            $row = Database::select(
5137
                'DISTINCT friend_user_id AS boss_id',
5138
                $userRelTable,
5139
                array(
5140
                    'where' => array(
5141
                        'user_id = ? AND relation_type = ? LIMIT 1' => array(
5142
                            $userId,
5143
                            USER_RELATION_TYPE_BOSS,
5144
                        )
5145
                    )
5146
                )
5147
            );
5148
            if (!empty($row)) {
5149
5150
                return $row[0]['boss_id'];
5151
            }
5152
        }
5153
5154
        return false;
5155
    }
5156
5157
    /**
5158
     * Get the boss user ID from a followed user id
5159
     * @param $userId
5160
     * @return bool
5161
     */
5162 View Code Duplication
    public static function getStudentBossList($userId)
5163
    {
5164
        $userId = intval($userId);
5165
        if ($userId > 0) {
5166
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5167
            $result = Database::select(
5168
                'DISTINCT friend_user_id AS boss_id',
5169
                $userRelTable,
5170
                array(
5171
                    'where' => array(
5172
                        'user_id = ? AND relation_type = ? ' => array(
5173
                            $userId,
5174
                            USER_RELATION_TYPE_BOSS,
5175
                        )
5176
                    )
5177
                ),
5178
                'all'
5179
            );
5180
5181
            return $result;
5182
        }
5183
5184
        return false;
5185
    }
5186
5187
    /**
5188
     * @param int $bossId
5189
     * @param int $studentId
5190
     *
5191
     * @return bool
5192
     */
5193
    public static function userIsBossOfStudent($bossId, $studentId)
5194
    {
5195
        $result = false;
5196
        $bossList = self::getStudentBossList($studentId);
5197
        if ($bossList) {
5198
            $bossList = array_column($bossList, 'boss_id');
5199
            if (in_array($bossId, $bossList)) {
5200
                $result = true;
5201
            }
5202
        }
5203
5204
        return $result;
5205
    }
5206
5207
    /**
5208
     * Get either a Gravatar URL or complete image tag for a specified email address.
5209
     *
5210
     * @param string $email The email address
5211
     * @param string $s Size in pixels, defaults to 80px [ 1 - 2048 ]
5212
     * @param string $d Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
5213
     * @param string $r Maximum rating (inclusive) [ g | pg | r | x ]
5214
     * @param boole $img True to return a complete IMG tag False for just the URL
5215
     * @param array $atts Optional, additional key/value attributes to include in the IMG tag
5216
     * @return String containing either just a URL or a complete image tag
5217
     * @source http://gravatar.com/site/implement/images/php/
5218
     */
5219
    private static function getGravatar(
5220
        $email,
5221
        $s = 80,
5222
        $d = 'mm',
5223
        $r = 'g',
5224
        $img = false,
5225
        $atts = array()
5226
    ) {
5227
        $url = 'http://www.gravatar.com/avatar/';
5228
        if (!empty($_SERVER['HTTPS'])) {
5229
            $url = 'https://secure.gravatar.com/avatar/';
5230
        }
5231
        $url .= md5(strtolower(trim($email)));
5232
        $url .= "?s=$s&d=$d&r=$r";
5233
        if ($img) {
5234
            $url = '<img src="'.$url.'"';
5235
            foreach ($atts as $key => $val)
5236
                $url .= ' '.$key.'="'.$val.'"';
5237
            $url .= ' />';
5238
        }
5239
        return $url;
5240
    }
5241
5242
    /**
5243
     * Displays the name of the user and makes the link to the user profile
5244
     * @param array $userInfo
5245
     *
5246
     * @return string
5247
     */
5248
    public static function getUserProfileLink($userInfo)
5249
    {
5250
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5251
            return Display::url(
5252
                $userInfo['complete_name_with_username'],
5253
                $userInfo['profile_url']
5254
            );
5255
        } else {
5256
            return get_lang('Anonymous');
5257
        }
5258
    }
5259
5260
    /**
5261
     * Displays the name of the user and makes the link to the user profile
5262
     *
5263
     * @param $userInfo
5264
     *
5265
     * @return string
5266
     */
5267
    public static function getUserProfileLinkWithPicture($userInfo)
5268
    {
5269
        return Display::url(Display::img($userInfo['avatar']), $userInfo['profile_url']);
5270
    }
5271
5272
    /**
5273
     * Get users whose name matches $firstname and $lastname
5274
     * @param string $firstname Firstname to search
5275
     * @param string $lastname Lastname to search
5276
     * @return array The user list
5277
     */
5278 View Code Duplication
    public static function getUserByName($firstname, $lastname)
5279
    {
5280
        $firstname = Database::escape_string($firstname);
5281
        $lastname = Database::escape_string($lastname);
5282
5283
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5284
5285
        $sql = <<<SQL
5286
            SELECT id, username, lastname, firstname
5287
            FROM $userTable
5288
            WHERE 
5289
                firstname LIKE '$firstname%' AND
5290
                lastname LIKE '$lastname%'
5291
SQL;
5292
5293
        $result = Database::query($sql);
5294
5295
        $users = [];
5296
        while ($resultData = Database::fetch_object($result)) {
5297
            $users[] = $resultData;
5298
        }
5299
5300
        return $users;
5301
    }
5302
5303
    /**
5304
     * @param int $optionSelected
5305
     * @return string
5306
     */
5307
    public static function getUserSubscriptionTab($optionSelected = 1)
5308
    {
5309
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5310
        if (($allowAdmin === 'true' && api_is_allowed_to_edit()) ||
5311
            api_is_platform_admin()
5312
        ) {
5313
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5314
5315
            $headers = [
5316
                [
5317
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5318
                    'content' => get_lang('Students'),
5319
                ],
5320
                [
5321
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5322
                    'content' => get_lang('Teachers'),
5323
                ],
5324
                /*[
5325
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5326
                    'content' => get_lang('Students'),
5327
                ],
5328
                [
5329
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5330
                    'content' => get_lang('Teachers'),
5331
                ],*/
5332
                [
5333
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5334
                    'content' => get_lang('Groups'),
5335
                ],
5336
                [
5337
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5338
                    'content' => get_lang('Classes'),
5339
                ]
5340
            ];
5341
5342
            return Display::tabsOnlyLink($headers, $optionSelected);
5343
        }
5344
    }
5345
5346
5347
    /**
5348
     * @param int $user_id
5349
     * @return bool
5350
     */
5351 View Code Duplication
    public static function user_is_online($user_id)
5352
    {
5353
        $track_online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5354
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5355
5356
        $access_url_id = api_get_current_access_url_id();
5357
        $time_limit = api_get_setting('display.time_limit_whosonline');
5358
5359
        $online_time = time() - $time_limit*60;
5360
        $limit_date = api_get_utc_datetime($online_time);
5361
        $user_id = intval($user_id);
5362
5363
        $query = " SELECT login_user_id,login_date
5364
               FROM $track_online_table track
5365
               INNER JOIN $table_user u ON (u.id=track.login_user_id)
5366
               WHERE
5367
                    track.access_url_id =  $access_url_id AND
5368
                    login_date >= '".$limit_date."'  AND
5369
                    u.id =  $user_id
5370
               LIMIT 1 ";
5371
5372
        $result = Database::query($query);
5373
        if (Database::num_rows($result)) {
5374
5375
            return true;
5376
        }
5377
5378
        return false;
5379
    }
5380
5381
    /**
5382
     * @param int $time_limit seconds
5383
     * @param bool $friends show friends (true) or all users (false)
5384
     * @return bool
5385
     */
5386
    public static function whoIsOnlineCount(
5387
        $time_limit = 0,
5388
        $friends = false
5389
    ) {
5390
        if (empty($time_limit)) {
5391
            $time_limit = api_get_setting('display.time_limit_whosonline');
5392
        } else {
5393
            $time_limit = intval($time_limit);
5394
        }
5395
        $track_online_table = Database::get_main_table(
5396
            TABLE_STATISTIC_TRACK_E_ONLINE
5397
        );
5398
        $friend_user_table = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5399
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5400
        $online_time = time() - $time_limit * 60;
5401
        $current_date = api_get_utc_datetime($online_time);
5402
5403
        if ($friends) {
5404
            // 	who friends from social network is online
5405
            $query = "SELECT DISTINCT count(login_user_id) as count
5406
				  FROM $track_online_table INNER JOIN $friend_user_table
5407
                  ON (friend_user_id = login_user_id)
5408
				  WHERE
5409
				        login_date >= '$current_date' AND
5410
				        friend_user_id <> '".api_get_user_id()."' AND
5411
				        relation_type='".USER_RELATION_TYPE_FRIEND."' AND
5412
				        user_id = '".api_get_user_id()."' ";
5413
        } else {
5414
            // All users online
5415
            $query = "SELECT count(login_id) as count
5416
                  FROM $track_online_table track INNER JOIN $table_user u
5417
                  ON (u.id=track.login_user_id)
5418
                  WHERE u.status != ".ANONYMOUS." AND login_date >= '$current_date'  ";
5419
        }
5420
5421
        if (api_get_multiple_access_url()) {
5422
            $access_url_id = api_get_current_access_url_id();
5423
            if ($access_url_id != -1) {
5424
                if ($friends) {
5425
                    // 	friends from social network is online
5426
                    $query = "SELECT DISTINCT count(login_user_id) as count
5427
							FROM $track_online_table track
5428
							INNER JOIN $friend_user_table ON (friend_user_id = login_user_id)
5429
							WHERE
5430
							    track.access_url_id = $access_url_id AND
5431
							    login_date >= '".$current_date."' AND
5432
							    friend_user_id <> '".api_get_user_id()."' AND
5433
							    relation_type='".USER_RELATION_TYPE_FRIEND."'  ";
5434
                } else {
5435
                    // all users online
5436
                    $query = "SELECT count(login_id) as count FROM $track_online_table  track
5437
                          INNER JOIN $table_user u ON (u.id=track.login_user_id)
5438
						  WHERE
5439
						    u.status != ".ANONYMOUS." AND
5440
						    track.access_url_id =  $access_url_id AND
5441
						    login_date >= '$current_date' ";
5442
                }
5443
            }
5444
        }
5445
5446
        // Dev purposes show all users online
5447
        /*$table_user = Database::get_main_table(TABLE_MAIN_USER);
5448
        $query = "SELECT count(*)  as count FROM ".$table_user;*/
5449
5450
        $result = Database::query($query);
5451
        if (Database::num_rows($result) > 0) {
5452
            $row = Database::fetch_array($result);
5453
5454
            return $row['count'];
5455
        } else {
5456
            return false;
5457
        }
5458
    }
5459
5460
    /**
5461
     * Gives a list of people online now (and in the last $valid minutes)
5462
     *
5463
     * @param int $from
5464
     * @param int $number_of_items
5465
     * @param string $column
5466
     * @param string $direction
5467
     * @param int $time_limit in seconds
5468
     * @param bool $friends show friends (true) or all users (false)
5469
     * @return array|bool
5470
     */
5471
    public static function whoIsOnline(
5472
        $from,
5473
        $number_of_items,
5474
        $column = '',
5475
        $direction = '',
5476
        $time_limit = 0,
5477
        $friends = false
5478
    ) {
5479
        // Time limit in seconds?
5480
        if (empty($time_limit)) {
5481
            $time_limit = api_get_setting('display.time_limit_whosonline');
5482
        } else {
5483
            $time_limit = intval($time_limit);
5484
        }
5485
5486
        $from = intval($from);
5487
        $number_of_items = intval($number_of_items);
5488
5489
        if (empty($column)) {
5490
            $column = 'picture_uri';
5491
            if ($friends) {
5492
                $column = 'login_date';
5493
            }
5494
        }
5495
5496
        if (empty($direction)) {
5497
            $direction = 'DESC';
5498
        } else {
5499
            if (!in_array(strtolower($direction), array('asc', 'desc'))) {
5500
                $direction = 'DESC';
5501
            }
5502
        }
5503
5504
        $online_time = time() - $time_limit * 60;
5505
        $current_date = api_get_utc_datetime($online_time);
5506
        $track_online_table = Database::get_main_table(
5507
            TABLE_STATISTIC_TRACK_E_ONLINE
5508
        );
5509
        $friend_user_table = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5510
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5511
5512
        if ($friends) {
5513
            // 	who friends from social network is online
5514
            $query = "SELECT DISTINCT login_user_id, login_date
5515
				  FROM $track_online_table INNER JOIN $friend_user_table
5516
				  ON (friend_user_id = login_user_id)
5517
				  WHERE
5518
				    login_date >= '".$current_date."' AND
5519
                    friend_user_id <> '".api_get_user_id()."' AND
5520
                    relation_type='".USER_RELATION_TYPE_FRIEND."' AND
5521
                    user_id = '".api_get_user_id()."'
5522
                  ORDER BY $column $direction
5523
                  LIMIT $from, $number_of_items";
5524
        } else {
5525
            $query = "SELECT DISTINCT login_user_id, login_date
5526
                    FROM ".$track_online_table." e
5527
		            INNER JOIN ".$table_user." u ON (u.id = e.login_user_id)
5528
                  WHERE u.status != ".ANONYMOUS." AND login_date >= '".$current_date."'
5529
                  ORDER BY $column $direction
5530
                  LIMIT $from, $number_of_items";
5531
        }
5532
5533
        if (api_get_multiple_access_url()) {
5534
            $access_url_id = api_get_current_access_url_id();
5535
            if ($access_url_id != -1) {
5536
                if ($friends) {
5537
                    // 	friends from social network is online
5538
                    $query = "SELECT distinct login_user_id, login_date
5539
							FROM $track_online_table track INNER JOIN $friend_user_table
5540
							ON (friend_user_id = login_user_id)
5541
							WHERE   track.access_url_id =  $access_url_id AND
5542
                                    login_date >= '".$current_date."' AND
5543
                                    friend_user_id <> '".api_get_user_id()."' AND
5544
                                    relation_type='".USER_RELATION_TYPE_FRIEND."'
5545
                            ORDER BY $column $direction
5546
                            LIMIT $from, $number_of_items";
5547
                } else {
5548
                    // all users online
5549
                    $query = "SELECT login_user_id, login_date
5550
						  FROM ".$track_online_table." track
5551
                          INNER JOIN ".$table_user." u
5552
                          ON (u.id=track.login_user_id)
5553
						  WHERE u.status != ".ANONYMOUS." AND track.access_url_id =  $access_url_id AND
5554
                                login_date >= '".$current_date."'
5555
                          ORDER BY $column $direction
5556
                          LIMIT $from, $number_of_items";
5557
                }
5558
            }
5559
        }
5560
5561
        //This query will show all registered users. Only for dev purposes.
5562
        /*$query = "SELECT DISTINCT u.id as login_user_id, login_date FROM ".$track_online_table ."  e , $table_user u
5563
                GROUP by u.id
5564
                ORDER BY $column $direction
5565
                LIMIT $from, $number_of_items";*/
5566
5567
        $result = Database::query($query);
5568
        if ($result) {
5569
            $users_online = array();
5570
            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...
5571
                $users_online[] = $login_user_id;
5572
            }
5573
5574
            return $users_online;
5575
        } else {
5576
            return false;
5577
        }
5578
    }
5579
5580
    /**
5581
     * @param int $user_id
5582
     * @param bool $is_time_over
5583
     * @param bool $get_count
5584
     * @param bool $reverse_order
5585
     * @param int $start
5586
     * @param null $maxPerPage
5587
     * @param null $categoryFilter
5588
     * @return array
5589
     */
5590
    public static function getCategories(
5591
        $user_id,
5592
        $is_time_over = false,
5593
        $get_count = false,
5594
        $reverse_order = false,
5595
        $start = 0,
5596
        $maxPerPage = null,
5597
        $categoryFilter = null
5598
    ) {
5599
        $tableSessionCategory = Database:: get_main_table(
5600
            TABLE_MAIN_SESSION_CATEGORY
5601
        );
5602
        $tableSession = Database:: get_main_table(TABLE_MAIN_SESSION);
5603
        $tableSessionUser = Database:: get_main_table(TABLE_MAIN_SESSION_USER);
5604
        $tableSessionCourseUser = Database:: get_main_table(
5605
            TABLE_MAIN_SESSION_COURSE_USER
5606
        );
5607
5608
        $select = " DISTINCT sc.id, sc.name  ";
5609
        if ($get_count) {
5610
            $select = " COUNT(DISTINCT(sc.id)) as total";
5611
        }
5612
5613
        $sql = "SELECT $select
5614
                FROM $tableSessionCategory sc
5615
                INNER JOIN $tableSession s ON (sc.id = s.session_category_id)
5616
                INNER JOIN (
5617
                    (
5618
                        SELECT DISTINCT session_id as sessionID FROM $tableSessionUser
5619
                        WHERE user_id = $user_id AND relation_type <> ".SESSION_RELATION_TYPE_RRHH."
5620
                    )
5621
                    UNION
5622
                    (
5623
                        SELECT DISTINCT s.id
5624
                        FROM $tableSession s
5625
                        WHERE (id_coach = $user_id)
5626
                    )
5627
                    UNION
5628
                    (
5629
                        SELECT DISTINCT s.id
5630
                        FROM $tableSessionUser su INNER JOIN $tableSession s
5631
                        ON (su.session_id = s.id)
5632
                        INNER JOIN $tableSessionCourseUser scu
5633
                        ON (scu.session_id = s.id)
5634
                        WHERE (scu.user_id = $user_id)
5635
                    )
5636
                ) as t ON (t.sessionId = sc.id)
5637
        ";
5638
5639
        if ($get_count) {
5640
            $result = Database::query($sql);
5641
            $row = Database::fetch_array($result);
5642
5643
            return $row['total'];
5644
        }
5645
5646
        $order = ' ORDER BY sc.name';
5647
        if ($reverse_order) {
5648
            $order = ' ORDER BY sc.name DESC ';
5649
        }
5650
5651
        $sql .= $order;
5652
5653 View Code Duplication
        if (isset($start) && isset($maxPerPage)) {
5654
            $start = intval($start);
5655
            $maxPerPage = intval($maxPerPage);
5656
            $limitCondition = " LIMIT $start, $maxPerPage";
5657
            $sql .= $limitCondition;
5658
        }
5659
5660
        $result = Database::query($sql);
5661
        $sessionsCategories = array();
5662
        if (Database::num_rows($result)) {
5663
            while ($sessionCategory = Database::fetch_array($result, 'ASSOC')) {
5664
                $sessions = self::get_sessions_by_category(
5665
                    $user_id,
5666
                    $is_time_over,
5667
                    false,
5668
                    $reverse_order,
5669
                    null,
5670
                    null,
5671
                    $sessionCategory['id']
5672
                );
5673
                $sessionsCategories[$sessionCategory['id']] = $sessions[$sessionCategory['id']];
5674
            }
5675
        }
5676
5677
        return $sessionsCategories;
5678
    }
5679
5680
5681
}
5682