Completed
Push — 1.10.x ( 954719...c312f5 )
by
unknown
47:45
created

UserManager::getUserSubscriptionTab()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 38
Code Lines 15

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 38
rs 8.5806
cc 4
eloc 15
nc 2
nop 1
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
5
use Chamilo\UserBundle\Entity\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, User.

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder;
7
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
8
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
9
use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder;
10
11
/**
12
 *
13
 * Class UserManager
14
 *
15
 * This library provides functions for user management.
16
 * Include/require it in your code to use its functionality.
17
 * @package chamilo.library
18
 * @author Julio Montoya <[email protected]> Social network groups added 2009/12
19
 *
20
 */
21
class UserManager
22
{
23
    // This constants are deprecated use the constants located in ExtraField
24
    const USER_FIELD_TYPE_TEXT = 1;
25
    const USER_FIELD_TYPE_TEXTAREA = 2;
26
    const USER_FIELD_TYPE_RADIO = 3;
27
    const USER_FIELD_TYPE_SELECT = 4;
28
    const USER_FIELD_TYPE_SELECT_MULTIPLE = 5;
29
    const USER_FIELD_TYPE_DATE = 6;
30
    const USER_FIELD_TYPE_DATETIME = 7;
31
    const USER_FIELD_TYPE_DOUBLE_SELECT = 8;
32
    const USER_FIELD_TYPE_DIVIDER = 9;
33
    const USER_FIELD_TYPE_TAG = 10;
34
    const USER_FIELD_TYPE_TIMEZONE = 11;
35
    const USER_FIELD_TYPE_SOCIAL_PROFILE = 12;
36
    const USER_FIELD_TYPE_FILE = 13;
37
    const USER_FIELD_TYPE_MOBILE_PHONE_NUMBER  = 14;
38
39
    private static $encryptionMethod;
40
41
    /**
42
     * The default constructor only instanciates an empty user object
43
     * @assert () === null
44
     */
45
    public function __construct()
46
    {
47
48
    }
49
50
    /**
51
     * Repository is use to query the DB, selects, etc
52
     * @return Chamilo\UserBundle\Entity\Repository\UserRepository
53
     */
54
    public static function getRepository()
55
    {
56
        return Database::getManager()->getRepository('ChamiloUserBundle:User');
57
    }
58
59
    /**
60
     * Create/update/delete methods are available in the UserManager
61
     * (based in the Sonata\UserBundle\Entity\UserManager)
62
     *
63
     * @return Chamilo\UserBundle\Entity\Manager\UserManager
64
     */
65
    public static function getManager()
66
    {
67
        $encoderFactory = self::getEncoderFactory();
68
69
        $userManager = new Chamilo\UserBundle\Entity\Manager\UserManager(
70
            $encoderFactory,
71
            new \FOS\UserBundle\Util\Canonicalizer(),
72
            new \FOS\UserBundle\Util\Canonicalizer(),
73
            Database::getManager(),
74
            'Chamilo\\UserBundle\\Entity\\User'
75
        );
76
77
        return $userManager;
78
    }
79
80
    /**
81
     * @param string $encryptionMethod
82
     */
83
    public static function setPasswordEncryption($encryptionMethod)
84
    {
85
        self::$encryptionMethod = $encryptionMethod;
86
    }
87
88
    /**
89
     * @return bool|mixed
90
     */
91
    public static function getPasswordEncryption()
92
    {
93
        $encryptionMethod = self::$encryptionMethod;
94
        if (empty($encryptionMethod)) {
95
            $encryptionMethod = api_get_configuration_value('password_encryption');
96
        }
97
98
        return $encryptionMethod;
99
    }
100
101
    /**
102
     * @return EncoderFactory
103
     */
104
    private static function getEncoderFactory()
105
    {
106
        $encryption = self::getPasswordEncryption();
107
        switch ($encryption) {
108
            case 'none':
109
                $defaultEncoder = new PlaintextPasswordEncoder();
110
                break;
111
            case 'sha1':
112
            case 'md5':
113
                $defaultEncoder = new MessageDigestPasswordEncoder($encryption, false, 1);
114
                break;
115
            case 'bcrypt':
116
                $defaultEncoder = new BCryptPasswordEncoder(4);
117
        }
118
119
        $encoders = array(
120
            'Chamilo\\UserBundle\\Entity\\User' => $defaultEncoder
121
        );
122
123
        $encoderFactory = new EncoderFactory($encoders);
124
125
        return $encoderFactory;
126
    }
127
128
    /**
129
     * @param User $user
130
     *
131
     * @return \Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface
132
     */
133
    private static function getEncoder(User $user)
134
    {
135
        $encoderFactory = self::getEncoderFactory();
136
137
        return $encoderFactory->getEncoder($user);
138
    }
139
140
    /**
141
     * Validates the password
142
     * @param string $password
143
     * @param User   $user
144
     *
145
     * @return bool
146
     */
147
    public static function isPasswordValid($password, User $user)
148
    {
149
        $encoder = self::getEncoder($user);
150
151
        $validPassword = $encoder->isPasswordValid(
152
            $user->getPassword(),
153
            $password,
154
            $user->getSalt()
155
        );
156
157
        return $validPassword;
158
    }
159
160
    /**
161
     * @param string $raw
162
     * @param User   $user
163
     *
164
     * @return bool
165
     */
166
    public static function encryptPassword($raw, User $user)
167
    {
168
        $encoder = self::getEncoder($user);
169
170
        $encodedPassword = $encoder->encodePassword(
171
            $raw,
172
            $user->getSalt()
173
        );
174
175
        return $encodedPassword;
176
    }
177
178
    /**
179
     * @param int $userId
180
     * @param string $password
181
     *
182
     */
183
    public static function updatePassword($userId, $password)
184
    {
185
        $repository = self::getRepository();
186
        /** @var User $user */
187
        $user = $repository->find($userId);
188
        $userManager = self::getManager();
189
        $user->setPlainPassword($password);
190
        $userManager->updateUser($user, true);
191
    }
192
193
    /**
194
     * Creates a new user for the platform
195
     * @author Hugues Peeters <[email protected]>,
196
     * @author Roan Embrechts <[email protected]>
197
     * @param  string Firstname
198
     * @param  string Lastname
199
     * @param  int    Status (1 for course tutor, 5 for student, 6 for anonymous)
200
     * @param  string e-mail address
201
     * @param  string Login
202
     * @param  string Password
203
     * @param  string Any official code (optional)
204
     * @param  string User language    (optional)
205
     * @param  string Phone number    (optional)
206
     * @param  string Picture URI        (optional)
207
     * @param  string Authentication source    (optional, defaults to 'platform', dependind on constant)
208
     * @param  string Account expiration date (optional, defaults to null)
209
     * @param  int     Whether the account is enabled or disabled by default
210
     * @param  int     The department of HR in which the user is registered (optional, defaults to 0)
211
     * @param  array Extra fields
212
     * @param  string Encrypt method used if password is given encrypted. Set to an empty string by default
213
     * @param  bool $send_mail
214
     * @param  bool $isAdmin
215
     *
216
     * @return mixed   new user id - if the new user creation succeeds, false otherwise
217
     * @desc The function tries to retrieve user id from the session.
218
     * If it exists, the current user id is the creator id. If a problem arises,
219
     * it stores the error message in global $api_failureList
220
     * @assert ('Sam','Gamegie',5,'[email protected]','jo','jo') > 1
221
     * @assert ('Pippin','Took',null,null,'jo','jo') === false
222
     */
223
    public static function create_user(
224
        $firstName,
225
        $lastName,
226
        $status,
227
        $email,
228
        $loginName,
229
        $password,
230
        $official_code = '',
231
        $language = '',
232
        $phone = '',
233
        $picture_uri = '',
234
        $auth_source = PLATFORM_AUTH_SOURCE,
235
        $expirationDate = null,
236
        $active = 1,
237
        $hr_dept_id = 0,
238
        $extra = null,
239
        $encrypt_method = '',
240
        $send_mail = false,
241
        $isAdmin = false
242
    ) {
243
        $currentUserId = api_get_user_id();
244
        $hook = HookCreateUser::create();
245
        if (!empty($hook)) {
246
            $hook->notifyCreateUser(HOOK_EVENT_TYPE_PRE);
247
        }
248
        global $_configuration;
249
        $original_password = $password;
250
        $access_url_id = 1;
251
252
        if (api_get_multiple_access_url()) {
253
            $access_url_id = api_get_current_access_url_id();
254
        }
255
256 View Code Duplication
        if (is_array($_configuration[$access_url_id]) &&
257
            isset($_configuration[$access_url_id]['hosting_limit_users']) &&
258
            $_configuration[$access_url_id]['hosting_limit_users'] > 0) {
259
            $num = self::get_number_of_users();
260
            if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
261
                api_warn_hosting_contact('hosting_limit_users');
262
                Display::addFlash(Display::return_message(get_lang('PortalUsersLimitReached'), 'warning'));
263
264
                return false;
265
            }
266
        }
267
268 View Code Duplication
        if ($status === 1 &&
269
            is_array($_configuration[$access_url_id]) &&
270
            isset($_configuration[$access_url_id]['hosting_limit_teachers']) &&
271
            $_configuration[$access_url_id]['hosting_limit_teachers'] > 0
272
        ) {
273
            $num = self::get_number_of_users(1);
274
            if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
275
                Display::addFlash(Display::return_message(get_lang('PortalTeachersLimitReached'), 'warning'));
276
                api_warn_hosting_contact('hosting_limit_teachers');
277
278
                return false;
279
            }
280
        }
281
282 View Code Duplication
        if (empty($password)) {
283
            Display::addFlash(Display::return_message(get_lang('ThisFieldIsRequired').': '.get_lang('Password') , 'warning'));
284
285
            return false;
286
        }
287
288
        // database table definition
289
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
290
291
        //Checking the user language
292
        $languages = api_get_languages();
293
        $language = strtolower($language);
294
        if (!in_array($language, $languages['folder'])) {
295
            $language = api_get_setting('platformLanguage');
296
        }
297
298
        if (!empty($currentUserId)) {
299
            $creator_id = $currentUserId;
300
        } else {
301
            $creator_id = 0;
302
        }
303
304
        // First check wether the login already exists
305
        if (!self::is_username_available($loginName)) {
306
            return api_set_failure('login-pass already taken');
307
        }
308
309
        $currentDate = api_get_utc_datetime();
310
        $now = new DateTime($currentDate);
311
312
        if (empty($expirationDate) || $expirationDate == '0000-00-00 00:00:00') {
313
            // Default expiration date
314
            // if there is a default duration of a valid account then
315
            // we have to change the expiration_date accordingly
316
            // Accept 0000-00-00 00:00:00 as a null value to avoid issues with
317
            // third party code using this method with the previous (pre-1.10)
318
            // value of 0000...
319
            if (api_get_setting('account_valid_duration') != '') {
320
                $expirationDate = new DateTime($currentDate);
321
                $days = intval(api_get_setting('account_valid_duration'));
322
                $expirationDate->modify('+'.$days.' day');
323
            }
324
        } else {
325
            $expirationDate = api_get_utc_datetime($expirationDate);
326
            $expirationDate = new \DateTime($expirationDate, new DateTimeZone('UTC'));
327
        }
328
329
        $userManager = self::getManager();
330
331
        /** @var User $user */
332
        $user = $userManager->createUser();
333
        $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 setStatus() does only exist in the following sub-classes of FOS\UserBundle\Model\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...
334
            ->setLastname($lastName)
335
            ->setFirstname($firstName)
336
            ->setUsername($loginName)
337
            ->setStatus($status)
338
            ->setPlainPassword($password)
339
            ->setEmail($email)
340
            ->setOfficialCode($official_code)
341
            ->setPictureUri($picture_uri)
342
            ->setCreatorId($creator_id)
343
            ->setAuthSource($auth_source)
344
            ->setPhone($phone)
345
            ->setLanguage($language)
346
            ->setRegistrationDate($now)
347
            ->setHrDeptId($hr_dept_id)
348
            ->setActive($active);
349
350
        if (!empty($expirationDate)) {
351
            $user->setExpirationDate($expirationDate);
352
        }
353
354
        $userManager->updateUser($user, true);
355
        $userId = $user->getId();
356
357
        if (!empty($userId)) {
358
            $return = $userId;
359
            $sql = "UPDATE $table_user SET user_id = $return WHERE id = $return";
360
            Database::query($sql);
361
362
            if ($isAdmin) {
363
                UserManager::add_user_as_admin($userId);
364
            }
365
366
            if (api_get_multiple_access_url()) {
367
                UrlManager::add_user_to_url($return, api_get_current_access_url_id());
368
            } else {
369
                //we are adding by default the access_url_user table with access_url_id = 1
370
                UrlManager::add_user_to_url($return, 1);
371
            }
372
373
            if (!empty($email) && $send_mail) {
374
                $recipient_name = api_get_person_name(
375
                    $firstName,
376
                    $lastName,
377
                    null,
378
                    PERSON_NAME_EMAIL_ADDRESS
379
                );
380
                $tplSubject = new Template(null, false, false, false, false, false);
381
                $layoutSubject = $tplSubject->get_template(
382
                    'mail/subject_registration_platform.tpl'
383
                );
384
                $emailSubject = $tplSubject->fetch($layoutSubject);
385
                $sender_name = api_get_person_name(
386
                    api_get_setting('administratorName'),
387
                    api_get_setting('administratorSurname'),
388
                    null,
389
                    PERSON_NAME_EMAIL_ADDRESS
390
                );
391
                $email_admin = api_get_setting('emailAdministrator');
392
393
                if (api_is_multiple_url_enabled()) {
394
                    $access_url_id = api_get_current_access_url_id();
395
                    if ($access_url_id != -1) {
396
                        $url = api_get_access_url($access_url_id);
397
                    }
398
                } else {
399
                    $url = api_get_path(WEB_PATH);
400
                }
401
                $tplContent = new Template(null, false, false, false, false, false);
402
                // variables for the default template
403
                $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
404
                $tplContent->assign('login_name', $loginName);
405
                $tplContent->assign('original_password', stripslashes($original_password));
406
                $tplContent->assign('mailWebPath', $url);
407
408
                $layoutContent = $tplContent->get_template('mail/content_registration_platform.tpl');
409
                $emailBody = $tplContent->fetch($layoutContent);
410
                /* MANAGE EVENT WITH MAIL */
411
                if (EventsMail::check_if_using_class('user_registration')) {
412
                    $values["about_user"] = $return;
413
                    $values["password"] = $original_password;
414
                    $values["send_to"] = array($return);
415
                    $values["prior_lang"] = null;
416
                    EventsDispatcher::events('user_registration', $values);
417
                } else {
418
                    $phoneNumber = isset($extra['mobile_phone_number']) ? $extra['mobile_phone_number'] : null;
419
420
                    $additionalParameters = array(
421
                        'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
422
                        'userId' => $return,
423
                        'mobilePhoneNumber' => $phoneNumber,
424
                        'password' => $original_password
425
                    );
426
427
                    api_mail_html(
428
                        $recipient_name,
429
                        $email,
430
                        $emailSubject,
431
                        $emailBody,
432
                        $sender_name,
433
                        $email_admin,
434
                        null,
435
                        null,
436
                        null,
437
                        $additionalParameters
438
                    );
439
                }
440
                /* ENDS MANAGE EVENT WITH MAIL */
441
            }
442
            Event::addEvent(LOG_USER_CREATE, LOG_USER_ID, $return);
443
        } else {
444
            return api_set_failure('error inserting in Database');
445
        }
446
447 View Code Duplication
        if (is_array($extra) && count($extra) > 0) {
448
            $res = true;
449
            foreach ($extra as $fname => $fvalue) {
450
                $res = $res && self::update_extra_field_value($return, $fname, $fvalue);
451
            }
452
        }
453
        self::update_extra_field_value($return, 'already_logged_in', 'false');
454
455
        if (!empty($hook)) {
456
            $hook->setEventData(array(
457
                'return' => $return,
458
                'originalPassword' => $original_password
459
            ));
460
            $hook->notifyCreateUser(HOOK_EVENT_TYPE_POST);
461
        }
462
463
        return $return;
464
    }
465
466
    /**
467
     * Can user be deleted? This function checks whether there's a course
468
     * in which the given user is the
469
     * only course administrator. If that is the case, the user can't be
470
     * deleted because the course would remain without a course admin.
471
     * @param int $user_id The user id
472
     * @return boolean true if user can be deleted
473
     * @assert (null) === false
474
     * @assert (-1) === false
475
     * @assert ('abc') === false
476
     */
477
    public static function can_delete_user($user_id)
478
    {
479
        $deny = api_get_configuration_value('deny_delete_users');
480
481
        if ($deny) {
482
            return false;
483
        }
484
485
        $table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
486
        if ($user_id != strval(intval($user_id))) {
487
            return false;
488
        }
489
        if ($user_id === false) {
490
            return false;
491
        }
492
        $sql = "SELECT * FROM $table_course_user
493
                WHERE status = 1 AND user_id = ".$user_id;
494
        $res = Database::query($sql);
495
        while ($course = Database::fetch_object($res)) {
496
            $sql = "SELECT id FROM $table_course_user
497
                    WHERE status=1 AND c_id = " . intval($course->c_id);
498
            $res2 = Database::query($sql);
499
            if (Database::num_rows($res2) == 1) {
500
501
                return false;
502
            }
503
        }
504
505
        return true;
506
    }
507
508
    /**
509
     * Delete a user from the platform, and all its belongings. This is a
510
     * very dangerous function that should only be accessible by
511
     * super-admins. Other roles should only be able to disable a user,
512
     * which removes access to the platform but doesn't delete anything.
513
     * @param int The ID of th user to be deleted
514
     * @return boolean true if user is successfully deleted, false otherwise
515
     * @assert (null) === false
516
     * @assert ('abc') === false
517
     */
518
    public static function delete_user($user_id)
519
    {
520
        if ($user_id != strval(intval($user_id))) {
521
            return false;
522
        }
523
524
        if ($user_id === false) {
525
            return false;
526
        }
527
528
        if (!self::can_delete_user($user_id)) {
529
            return false;
530
        }
531
532
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
533
        $usergroup_rel_user = Database :: get_main_table(TABLE_USERGROUP_REL_USER);
534
        $table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
535
        $table_course = Database :: get_main_table(TABLE_MAIN_COURSE);
536
        $table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
537
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
538
        $table_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
539
        $table_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
540
        $table_group = Database :: get_course_table(TABLE_GROUP_USER);
541
        $table_work = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
542
543
        // Unsubscribe the user from all groups in all his courses
544
        $sql = "SELECT c.id FROM $table_course c, $table_course_user cu
545
                WHERE
546
                    cu.user_id = '".$user_id."' AND
547
                    relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
548
                    c.id = cu.c_id";
549
550
        $res = Database::query($sql);
551
        while ($course = Database::fetch_object($res)) {
552
            $sql = "DELETE FROM $table_group
553
                    WHERE c_id = {$course->id} AND user_id = $user_id";
554
            Database::query($sql);
555
        }
556
557
        // Unsubscribe user from usergroup_rel_user
558
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
559
        Database::query($sql);
560
561
        // Unsubscribe user from all courses
562
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
563
        Database::query($sql);
564
565
        // Unsubscribe user from all courses in sessions
566
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
567
        Database::query($sql);
568
569
        // If the user was added as a id_coach then set the current admin as coach see BT#
570
        $currentUserId = api_get_user_id();
571
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
572
                WHERE id_coach = '".$user_id."'";
573
        Database::query($sql);
574
575
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
576
                WHERE session_admin_id = '".$user_id."'";
577
        Database::query($sql);
578
579
        // Unsubscribe user from all sessions
580
        $sql = "DELETE FROM $table_session_user
581
                WHERE user_id = '".$user_id."'";
582
        Database::query($sql);
583
584
        // Delete user picture
585
        /* TODO: Logic about api_get_setting('split_users_upload_directory') == 'true'
586
        a user has 4 different sized photos to be deleted. */
587
        $user_info = api_get_user_info($user_id);
588
589
        if (strlen($user_info['picture_uri']) > 0) {
590
            $path = self::getUserPathById($user_id, 'system');
591
            $img_path = $path.$user_info['picture_uri'];
592
            if (file_exists($img_path)) {
593
                unlink($img_path);
594
            }
595
        }
596
597
        // Delete the personal course categories
598
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
599
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
600
        Database::query($sql);
601
602
        // Delete user from the admin table
603
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
604
        Database::query($sql);
605
606
        // Delete the personal agenda-items from this user
607
        $agenda_table = Database :: get_main_table(TABLE_PERSONAL_AGENDA);
608
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
609
        Database::query($sql);
610
611
        $gradebook_results_table = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
612
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
613
        Database::query($sql);
614
615
        $extraFieldValue = new ExtraFieldValue('user');
616
        $extraFieldValue->deleteValuesByItem($user_id);
617
618
        UrlManager::deleteUserFromAllUrls($user_id);
619
620
        if (api_get_setting('allow_social_tool') == 'true') {
621
            $userGroup = new UserGroup();
622
            //Delete user from portal groups
623
            $group_list = $userGroup->get_groups_by_user($user_id);
624
            if (!empty($group_list)) {
625
                foreach ($group_list as $group_id => $data) {
626
                    $userGroup->delete_user_rel_group($user_id, $group_id);
627
                }
628
            }
629
630
            // Delete user from friend lists
631
            SocialManager::remove_user_rel_user($user_id, true);
632
        }
633
634
        // Removing survey invitation
635
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
636
637
        // Delete students works
638
        $sql = "DELETE FROM $table_work WHERE user_id = $user_id AND c_id <> 0";
639
        Database::query($sql);
640
641
        $sql = "UPDATE c_item_property SET to_user_id = NULL
642
                WHERE to_user_id = '".$user_id."'";
643
        Database::query($sql);
644
645
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
646
                WHERE insert_user_id = '".$user_id."'";
647
        Database::query($sql);
648
649
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
650
                WHERE lastedit_user_id = '".$user_id."'";
651
        Database::query($sql);
652
653
        // Delete user from database
654
        $sql = "DELETE FROM $table_user WHERE id = '".$user_id."'";
655
        Database::query($sql);
656
657
        // Add event to system log
658
        $user_id_manager = api_get_user_id();
659
660
        Event::addEvent(
661
            LOG_USER_DELETE,
662
            LOG_USER_ID,
663
            $user_id,
664
            api_get_utc_datetime(),
665
            $user_id_manager
666
        );
667
668
        Event::addEvent(
669
            LOG_USER_DELETE,
670
            LOG_USER_OBJECT,
671
            $user_info,
672
            api_get_utc_datetime(),
673
            $user_id_manager
674
        );
675
676
        return true;
677
    }
678
679
    /**
680
     * Deletes users completely. Can be called either as:
681
     * - UserManager :: delete_users(1, 2, 3); or
682
     * - UserManager :: delete_users(array(1, 2, 3));
683
     * @param array|int $ids
684
     * @return boolean  True if at least one user was successfuly deleted. False otherwise.
685
     * @author Laurent Opprecht
686
     * @uses UserManager::delete_user() to actually delete each user
687
     * @assert (null) === false
688
     * @assert (-1) === false
689
     * @assert (array(-1)) === false
690
     */
691
    public static function delete_users($ids = array())
692
    {
693
        $result = false;
694
        $ids = is_array($ids) ? $ids : func_get_args();
695
        if (!is_array($ids) or count($ids) == 0) { return false; }
696
        $ids = array_map('intval', $ids);
697
        foreach ($ids as $id) {
698
            if (empty($id) or $id < 1) { continue; }
699
            $deleted = self::delete_user($id);
700
            $result = $deleted || $result;
701
        }
702
703
        return $result;
704
    }
705
706
    /**
707
     * Disable users. Can be called either as:
708
     * - UserManager :: deactivate_users(1, 2, 3);
709
     * - UserManager :: deactivate_users(array(1, 2, 3));
710
     * @param array|int $ids
711
     * @return boolean
712
     * @author Laurent Opprecht
713
     * @assert (null) === false
714
     * @assert (array(-1)) === false
715
     */
716 View Code Duplication
    public static function deactivate_users($ids = array())
717
    {
718
        if (empty($ids)) {
719
            return false;
720
        }
721
722
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
723
724
        $ids = is_array($ids) ? $ids : func_get_args();
725
        $ids = array_map('intval', $ids);
726
        $ids = implode(',', $ids);
727
728
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
729
        $r = Database::query($sql);
730
        if ($r !== false) {
731
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
732
        }
733
        return $r;
734
    }
735
736
    /**
737
     * Enable users. Can be called either as:
738
     * - UserManager :: activate_users(1, 2, 3);
739
     * - UserManager :: activate_users(array(1, 2, 3));
740
     * @param array|int IDs of the users to enable
741
     * @return boolean
742
     * @author Laurent Opprecht
743
     * @assert (null) === false
744
     * @assert (array(-1)) === false
745
     */
746 View Code Duplication
    public static function activate_users($ids = array())
747
    {
748
        if (empty($ids)) {
749
            return false;
750
        }
751
752
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
753
754
        $ids = is_array($ids) ? $ids : func_get_args();
755
        $ids = array_map('intval', $ids);
756
        $ids = implode(',', $ids);
757
758
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
759
        $r = Database::query($sql);
760
        if ($r !== false) {
761
            Event::addEvent(LOG_USER_ENABLE,LOG_USER_ID,$ids);
762
        }
763
        return $r;
764
    }
765
766
    /**
767
     * Update user information with new openid
768
     * @param int $user_id
769
     * @param string $openid
770
     * @return boolean true if the user information was updated
771
     * @assert (false,'') === false
772
     * @assert (-1,'') === false
773
     */
774
    public static function update_openid($user_id, $openid)
775
    {
776
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
777
        if ($user_id != strval(intval($user_id)))
778
            return false;
779
        if ($user_id === false)
780
            return false;
781
        $sql = "UPDATE $table_user SET
782
                openid='".Database::escape_string($openid)."'";
783
        $sql .= " WHERE id= $user_id";
784
        return Database::query($sql);
785
    }
786
787
    /**
788
     * Update user information with all the parameters passed to this function
789
     * @param int The ID of the user to be updated
790
     * @param string The user's firstname
791
     * @param string The user's lastname
792
     * @param string The user's username (login)
793
     * @param string The user's password
794
     * @param string The authentication source (default: "platform")
795
     * @param string The user's e-mail address
796
     * @param int The user's status
797
     * @param string The user's official code (usually just an internal institutional code)
798
     * @param string The user's phone number
799
     * @param string The user's picture URL (internal to the Chamilo directory)
800
     * @param int The user ID of the person who registered this user (optional, defaults to null)
801
     * @param int The department of HR in which the user is registered (optional, defaults to 0)
802
     * @param array A series of additional fields to add to this user as extra fields (optional, defaults to null)
803
     * @return boolean|integer False on error, or the user ID if the user information was updated
804
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
805
     */
806
    public static function update_user(
807
        $user_id,
808
        $firstname,
809
        $lastname,
810
        $username,
811
        $password = null,
812
        $auth_source = null,
813
        $email,
814
        $status,
815
        $official_code,
816
        $phone,
817
        $picture_uri,
818
        $expiration_date,
819
        $active,
820
        $creator_id = null,
821
        $hr_dept_id = 0,
822
        $extra = null,
823
        $language = 'english',
824
        $encrypt_method = '',
825
        $send_email = false,
826
        $reset_password = 0
827
    ) {
828
        $hook = HookUpdateUser::create();
829
        if (!empty($hook)) {
830
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_PRE);
831
        }
832
        global $_configuration;
833
        $original_password = $password;
834
835
        if (empty($user_id)) {
836
            return false;
837
        }
838
        $user_info = api_get_user_info($user_id, false, true);
839
840
        if ($reset_password == 0) {
841
            $password = null;
842
            $auth_source = $user_info['auth_source'];
843
        } elseif ($reset_password == 1) {
844
            $original_password = $password = api_generate_password();
845
            $auth_source = PLATFORM_AUTH_SOURCE;
846
        } elseif ($reset_password == 2) {
847
            $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...
848
            $auth_source = PLATFORM_AUTH_SOURCE;
849
        } elseif ($reset_password == 3) {
850
            $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...
851
            $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...
852
        }
853
854
        if ($user_id != strval(intval($user_id))) {
855
            return false;
856
        }
857
858
        if ($user_id === false) {
859
            return false;
860
        }
861
862
        //Checking the user language
863
        $languages = api_get_languages();
864
        if (!in_array($language, $languages['folder'])) {
865
            $language = api_get_setting('platformLanguage');
866
        }
867
868
        $change_active = 0;
869
        if ($user_info['active'] != $active) {
870
            $change_active = 1;
871
        }
872
873
        $userManager = self::getManager();
874
875
        /** @var Chamilo\UserBundle\Entity\User $user */
876
        $user = self::getRepository()->find($user_id);
877
878
        if (empty($user)) {
879
            return false;
880
        }
881
882
        if (!empty($expiration_date)) {
883
            $expiration_date = api_get_utc_datetime($expiration_date);
884
            $expiration_date = new \DateTime(
885
                $expiration_date,
886
                new DateTimeZone('UTC')
887
            );
888
        }
889
890
        $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 setStatus() does only exist in the following sub-classes of FOS\UserBundle\Model\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...
891
            ->setLastname($lastname)
892
            ->setFirstname($firstname)
893
            ->setUsername($username)
894
            ->setStatus($status)
895
            ->setAuthSource($auth_source)
896
            ->setLanguage($language)
897
            ->setEmail($email)
898
            ->setOfficialCode($official_code)
899
            ->setPhone($phone)
900
            ->setPictureUri($picture_uri)
901
            ->setExpirationDate($expiration_date)
902
            ->setActive($active)
903
            ->setHrDeptId($hr_dept_id)
904
        ;
905
906
        if (!is_null($password)) {
907
            $user->setPlainPassword($password);
908
        }
909
910
        $userManager->updateUser($user, true);
911
912
        if ($change_active == 1) {
913
            if ($active == 1) {
914
                $event_title = LOG_USER_ENABLE;
915
            } else {
916
                $event_title = LOG_USER_DISABLE;
917
            }
918
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
919
        }
920
921 View Code Duplication
        if (is_array($extra) && count($extra) > 0) {
922
            $res = true;
923
            foreach ($extra as $fname => $fvalue) {
924
                $res = $res && self::update_extra_field_value(
925
                    $user_id,
926
                    $fname,
927
                    $fvalue
928
                );
929
            }
930
        }
931
932
        if (!empty($email) && $send_email) {
933
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
934
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('YourReg').' '.api_get_setting('siteName');
935
            $sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);
936
            $email_admin = api_get_setting('emailAdministrator');
937
938
            if (api_is_multiple_url_enabled()) {
939
                $access_url_id = api_get_current_access_url_id();
940
                if ($access_url_id != -1) {
941
                    $url = api_get_access_url($access_url_id);
942
                    $emailbody = get_lang('Dear')." ".stripslashes(api_get_person_name($firstname, $lastname)).",\n\n".get_lang('YouAreReg')." ".api_get_setting('siteName')." ".get_lang('WithTheFollowingSettings')."\n\n".get_lang('Username')." : ".$username.(($reset_password > 0) ? "\n".get_lang('Pass')." : ".stripslashes($original_password) : "")."\n\n".get_lang('Address')." ".api_get_setting('siteName')." ".get_lang('Is')." : ".$url['url']."\n\n".get_lang('Problem')."\n\n".get_lang('SignatureFormula').",\n\n".api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".get_lang('Manager')." ".api_get_setting('siteName')."\nT. ".api_get_setting('administratorTelephone')."\n".get_lang('Email')." : ".api_get_setting('emailAdministrator');
943
                }
944
            } else {
945
                $emailbody = get_lang('Dear')." ".stripslashes(api_get_person_name($firstname, $lastname)).",\n\n".get_lang('YouAreReg')." ".api_get_setting('siteName')." ".get_lang('WithTheFollowingSettings')."\n\n".get_lang('Username')." : ".$username.(($reset_password > 0) ? "\n".get_lang('Pass')." : ".stripslashes($original_password) : "")."\n\n".get_lang('Address')." ".api_get_setting('siteName')." ".get_lang('Is')." : ".$_configuration['root_web']."\n\n".get_lang('Problem')."\n\n".get_lang('SignatureFormula').",\n\n".api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".get_lang('Manager')." ".api_get_setting('siteName')."\nT. ".api_get_setting('administratorTelephone')."\n".get_lang('Email')." : ".api_get_setting('emailAdministrator');
946
            }
947
948
            $emailbody = nl2br($emailbody);
949
            api_mail_html(
950
                $recipient_name,
951
                $email,
952
                $emailsubject,
953
                $emailbody,
954
                $sender_name,
955
                $email_admin
956
            );
957
        }
958
959
        if (!empty($hook)) {
960
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_POST);
961
        }
962
963
        return $user->getId();
964
    }
965
966
    /**
967
     * Disables or enables a user
968
     * @param int user_id
969
     * @param int Enable or disable
970
     * @return void
971
     * @assert (-1,0) === false
972
     * @assert (1,1) === true
973
     */
974
    private static function change_active_state($user_id, $active)
975
    {
976
        if (strval(intval($user_id)) != $user_id) {
977
            return false;
978
        }
979
        if ($user_id < 1) {
980
            return false;
981
        }
982
        $user_id = intval($user_id);
983
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
984
        $sql = "UPDATE $table_user SET active = '$active' WHERE id = $user_id";
985
        $r = Database::query($sql);
986
        $ev = LOG_USER_DISABLE;
987
        if ($active == 1) {
988
            $ev = LOG_USER_ENABLE;
989
        }
990
        if ($r !== false) {
991
            Event::addEvent($ev, LOG_USER_ID, $user_id);
992
        }
993
994
        return $r;
995
    }
996
997
    /**
998
     * Disables a user
999
     * @param int User id
1000
     * @return bool
1001
     * @uses UserManager::change_active_state() to actually disable the user
1002
     * @assert (0) === false
1003
     */
1004
    public static function disable($user_id)
1005
    {
1006
        if (empty($user_id)) {
1007
            return false;
1008
        }
1009
        self::change_active_state($user_id, 0);
1010
        return true;
1011
    }
1012
1013
    /**
1014
     * Enable a user
1015
     * @param int User id
1016
     * @return bool
1017
     * @uses UserManager::change_active_state() to actually disable the user
1018
     * @assert (0) === false
1019
     */
1020
    public static function enable($user_id)
1021
    {
1022
        if (empty($user_id)) {
1023
            return false;
1024
        }
1025
        self::change_active_state($user_id, 1);
1026
        return true;
1027
    }
1028
1029
    /**
1030
     * Returns the user's id based on the original id and field name in
1031
     * the extra fields. Returns 0 if no user was found. This function is
1032
     * mostly useful in the context of a web services-based sinchronization
1033
     * @param string Original user id
1034
     * @param string Original field name
1035
     * @return int User id
1036
     * @assert ('0','---') === 0
1037
     */
1038 View Code Duplication
    public static function get_user_id_from_original_id($original_user_id_value, $original_user_id_name)
1039
    {
1040
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1041
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1042
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1043
        $sql = "SELECT item_id as user_id
1044
                FROM $t_uf uf
1045
                INNER JOIN $t_ufv ufv
1046
                ON ufv.field_id=uf.id
1047
                WHERE
1048
                    variable='$original_user_id_name' AND
1049
                    value='$original_user_id_value' AND
1050
                    extra_field_type = $extraFieldType
1051
                ";
1052
        $res = Database::query($sql);
1053
        $row = Database::fetch_object($res);
1054
        if ($row) {
1055
            return $row->user_id;
1056
        } else {
1057
            return 0;
1058
        }
1059
    }
1060
1061
    /**
1062
     * Check if a username is available
1063
     * @param string the wanted username
1064
     * @return boolean true if the wanted username is available
1065
     * @assert ('') === false
1066
     * @assert ('xyzxyzxyz') === true
1067
     */
1068
    public static function is_username_available($username)
1069
    {
1070
        if (empty($username)) {
1071
            return false;
1072
        }
1073
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
1074
        $sql = "SELECT username FROM $table_user
1075
                WHERE username = '".Database::escape_string($username)."'";
1076
        $res = Database::query($sql);
1077
        return Database::num_rows($res) == 0;
1078
    }
1079
1080
    /**
1081
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1082
     * @param string $firstname The first name of the user.
1083
     * @param string $lastname The last name of the user.
1084
     * @param string $language (optional)    The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1085
     * @param string $encoding (optional)    The character encoding for the input names. If it is omitted, the platform character set will be used by default.
1086
     * @return string Suggests a username that contains only ASCII-letters and digits, without check for uniqueness within the system.
1087
     * @author Julio Montoya Armas
1088
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1089
     * @assert ('','') === false
1090
     * @assert ('a','b') === 'ab'
1091
     */
1092
    public static function create_username($firstname, $lastname, $language = null, $encoding = null)
1093
    {
1094
        if (empty($firstname) && empty($lastname)) {
1095
            return false;
1096
        }
1097
1098
        $firstname = api_substr(preg_replace(USERNAME_PURIFIER, '', $firstname), 0, 1); // The first letter only.
1099
        //Looking for a space in the lastname
1100
        $pos = api_strpos($lastname, ' ');
1101
        if ($pos !== false) {
1102
            $lastname = api_substr($lastname, 0, $pos);
1103
        }
1104
1105
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1106
        $username = $firstname.$lastname;
1107
        if (empty($username)) {
1108
            $username = 'user';
1109
        }
1110
1111
        $username = URLify::transliterate($username);
1112
1113
        return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3));
1114
    }
1115
1116
    /**
1117
     * Creates a unique username, using:
1118
     * 1. the first name and the last name of a user;
1119
     * 2. an already created username but not checked for uniqueness yet.
1120
     * @param string $firstname                The first name of a given user. If the second parameter $lastname is NULL, then this
1121
     * parameter is treated as username which is to be checked for uniqueness and to be modified when it is necessary.
1122
     * @param string $lastname                The last name of the user.
1123
     * @param string $language (optional)    The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1124
     * @param string $encoding (optional)    The character encoding for the input names. If it is omitted, the platform character set will be used by default.
1125
     * @return string                        Returns a username that contains only ASCII-letters and digits, and that is unique within the system.
1126
     * Note: When the method is called several times with same parameters, its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1127
     * @author Ivan Tcholakov, 2009
1128
     */
1129
    public static function create_unique_username($firstname, $lastname = null, $language = null, $encoding = null)
1130
    {
1131
        if (is_null($lastname)) {
1132
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1133
            // For making this method tolerant of mistakes, let us transliterate and purify the suggested input username anyway.
1134
            // So, instead of the sentence $username = $firstname; we place the following:
1135
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1136
        } else {
1137
            $username = self::create_username($firstname, $lastname, $language, $encoding);
1138
        }
1139
        if (!self::is_username_available($username)) {
1140
            $i = 2;
1141
            $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1142
            while (!self::is_username_available($temp_username)) {
1143
                $i++;
1144
                $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1145
            }
1146
            $username = $temp_username;
1147
        }
1148
1149
        $username = URLify::transliterate($username);
1150
1151
        return $username;
1152
    }
1153
1154
    /**
1155
     * Modifies a given username accordingly to the specification for valid characters and length.
1156
     * @param $username string                The input username.
1157
     * @param bool $strict (optional)        When this flag is TRUE, the result is guaranteed for full compliance, otherwise compliance may be partial. The default value is FALSE.
1158
     * @param string $encoding (optional)    The character encoding for the input names. If it is omitted, the platform character set will be used by default.
1159
     * @return string                        The resulting purified username.
1160
     */
1161
    public static function purify_username($username, $strict = false, $encoding = null)
1162
    {
1163
        if ($strict) {
1164
            // 1. Conversion of unacceptable letters (latinian letters with accents for example) into ASCII letters in order they not to be totally removed.
1165
            // 2. Applying the strict purifier.
1166
            // 3. Length limitation.
1167
            $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);
1168
            $return = URLify::transliterate($return);
1169
            return $return;
1170
        }
1171
        // 1. Applying the shallow purifier.
1172
        // 2. Length limitation.
1173
        return substr(preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username), 0, USERNAME_MAX_LENGTH);
1174
    }
1175
1176
    /**
1177
     * Checks whether the user id exists in the database
1178
     *
1179
     * @param int User id
1180
     * @return bool True if user id was found, false otherwise
1181
     */
1182 View Code Duplication
    public static function is_user_id_valid($userId)
1183
    {
1184
        $resultData = Database::select(
1185
            'COUNT(1) AS count',
1186
            Database::get_main_table(TABLE_MAIN_USER),
1187
            [
1188
                'where' => ['id = ?' => intval($userId)]
1189
            ],
1190
            'first'
1191
        );
1192
1193
        if ($resultData === false) {
1194
            return false;
1195
        }
1196
1197
        return $resultData['count'] > 0;
1198
    }
1199
1200
    /**
1201
     * Checks whether a given username matches to the specification strictly. The empty username is assumed here as invalid.
1202
     * Mostly this function is to be used in the user interface built-in validation routines for providing feedback while usernames are enterd manually.
1203
     * @param string $username The input username.
1204
     * @param string $encoding (optional) The character encoding for the input names. If it is omitted, the platform character set will be used by default.
1205
     * @return bool Returns TRUE if the username is valid, FALSE otherwise.
1206
     */
1207
    public static function is_username_valid($username, $encoding = null)
1208
    {
1209
        return !empty($username) && $username == self::purify_username($username, true);
1210
    }
1211
1212
    /**
1213
     * Checks whether a username is empty. If the username contains whitespace characters, such as spaces, tabulators, newlines, etc.,
1214
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1215
     * @param string $username The given username.
1216
     * @return bool  Returns TRUE if length of the username exceeds the limit, FALSE otherwise.
1217
     */
1218
    public static function is_username_empty($username)
1219
    {
1220
        return (strlen(self::purify_username($username, false)) == 0);
1221
    }
1222
1223
    /**
1224
     * Checks whether a username is too long or not.
1225
     * @param string $username The given username, it should contain only ASCII-letters and digits.
1226
     * @return bool Returns TRUE if length of the username exceeds the limit, FALSE otherwise.
1227
     */
1228
    public static function is_username_too_long($username)
1229
    {
1230
        return (strlen($username) > USERNAME_MAX_LENGTH);
1231
    }
1232
1233
    /**
1234
    * Get the users by ID
1235
    * @param array $ids student ids
1236
    * @param string $active
1237
    * @param string $order
1238
    * @param string $limit
1239
    * @return array $result student information
1240
    */
1241
    public static function get_user_list_by_ids($ids = array(), $active = null, $order = null, $limit = null)
1242
    {
1243
        if (empty($ids)) {
1244
            return array();
1245
        }
1246
1247
        $ids = is_array($ids) ? $ids : array($ids);
1248
        $ids = array_map('intval', $ids);
1249
        $ids = implode(',', $ids);
1250
1251
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1252
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1253
        if (!is_null($active)) {
1254
            $sql .= ' AND active='.($active ? '1' : '0');
1255
        }
1256
1257
        if (!is_null($order)) {
1258
            $order = Database::escape_string($order);
1259
            $sql .= ' ORDER BY ' . $order;
1260
        }
1261
1262
        if (!is_null($limit)) {
1263
            $limit = Database::escape_string($limit);
1264
            $sql .= ' LIMIT ' . $limit;
1265
        }
1266
1267
        $rs = Database::query($sql);
1268
        $result = array();
1269
        while ($row = Database::fetch_array($rs)) {
1270
            $result[] = $row;
1271
        }
1272
1273
        return $result;
1274
    }
1275
1276
    /**
1277
     * Get a list of users of which the given conditions match with an = 'cond'
1278
     * @param array $conditions a list of condition (exemple : status=>STUDENT)
1279
     * @param array $order_by a list of fields on which sort
1280
     * @return array An array with all users of the platform.
1281
     * @todo optional course code parameter, optional sorting parameters...
1282
     * @todo security filter order by
1283
     */
1284
    public static function get_user_list(
1285
        $conditions = array(),
1286
        $order_by = array(),
1287
        $limit_from = false,
1288
        $limit_to = false
1289
    ) {
1290
        $user_table = Database :: get_main_table(TABLE_MAIN_USER);
1291
        $return_array = array();
1292
        $sql_query = "SELECT * FROM $user_table";
1293
        if (count($conditions) > 0) {
1294
            $sql_query .= ' WHERE ';
1295
            foreach ($conditions as $field => $value) {
1296
                $field = Database::escape_string($field);
1297
                $value = Database::escape_string($value);
1298
                $sql_query .= "$field = '$value'";
1299
            }
1300
        }
1301 View Code Duplication
        if (count($order_by) > 0) {
1302
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1303
        }
1304
1305
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1306
            $limit_from = intval($limit_from);
1307
            $limit_to = intval($limit_to);
1308
            $sql_query .= " LIMIT $limit_from, $limit_to";
1309
        }
1310
        $sql_result = Database::query($sql_query);
1311
        while ($result = Database::fetch_array($sql_result)) {
1312
            $return_array[] = $result;
1313
        }
1314
        return $return_array;
1315
    }
1316
1317
    /**
1318
     * Get a list of users of which the given conditions match with a LIKE '%cond%'
1319
     * @param array $conditions a list of condition (exemple : status=>STUDENT)
1320
     * @param array $order_by a list of fields on which sort
1321
     * @return array An array with all users of the platform.
1322
     * @todo optional course code parameter, optional sorting parameters...
1323
     * @todo security filter order_by
1324
     */
1325
    public static function get_user_list_like(
1326
        $conditions = array(),
1327
        $order_by = array(),
1328
        $simple_like = false,
1329
        $condition = 'AND'
1330
    ) {
1331
        $user_table = Database :: get_main_table(TABLE_MAIN_USER);
1332
        $return_array = array();
1333
        $sql_query = "SELECT * FROM $user_table";
1334
        if (count($conditions) > 0) {
1335
            $sql_query .= ' WHERE ';
1336
            $temp_conditions = array();
1337
            foreach ($conditions as $field => $value) {
1338
                $field = Database::escape_string($field);
1339
                $value = Database::escape_string($value);
1340 View Code Duplication
                if ($simple_like) {
1341
                    $temp_conditions[] = $field." LIKE '$value%'";
1342
                } else {
1343
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1344
                }
1345
            }
1346
            if (!empty($temp_conditions)) {
1347
                $sql_query .= implode(' '.$condition.' ', $temp_conditions);
1348
            }
1349
        }
1350 View Code Duplication
        if (count($order_by) > 0) {
1351
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1352
        }
1353
        $sql_result = Database::query($sql_query);
1354
        while ($result = Database::fetch_array($sql_result)) {
1355
            $return_array[] = $result;
1356
        }
1357
        return $return_array;
1358
    }
1359
1360
    /**
1361
     * Get user picture URL or path from user ID (returns an array).
1362
     * The return format is a complete path, enabling recovery of the directory
1363
     * with dirname() or the file with basename(). This also works for the
1364
     * functions dealing with the user's productions, as they are located in
1365
     * the same directory.
1366
     * @param   integer   $id User ID
1367
     * @param   string    $type Type of path to return (can be 'system', 'web')
1368
     * @param   array $userInfo user information to avoid query the DB
1369
     * returns the /main/img/unknown.jpg image set it at true
1370
     *
1371
     * @return    array     Array of 2 elements: 'dir' and 'file' which contain
1372
     * the dir and file as the name implies if image does not exist it will
1373
     * return the unknow image if anonymous parameter is true if not it returns an empty array
1374
     */
1375
    public static function get_user_picture_path_by_id($id, $type = 'web', $userInfo = [])
1376
    {
1377
        switch ($type) {
1378
            case 'system': // Base: absolute system path.
1379
                $base = api_get_path(SYS_CODE_PATH);
1380
                break;
1381
            case 'web': // Base: absolute web path.
1382
            default:
1383
                $base = api_get_path(WEB_CODE_PATH);
1384
                break;
1385
        }
1386
1387
        $anonymousPath = array(
1388
            'dir' => $base.'img/',
1389
            'file' => 'unknown.jpg',
1390
            'email' => '',
1391
        );
1392
1393
        if (empty($id) || empty($type)) {
1394
            return $anonymousPath;
1395
        }
1396
1397
        $id = intval($id);
1398 View Code Duplication
        if (empty($userInfo)) {
1399
            $user_table = Database:: get_main_table(TABLE_MAIN_USER);
1400
            $sql = "SELECT email, picture_uri FROM $user_table
1401
                    WHERE id=".$id;
1402
            $res = Database::query($sql);
1403
1404
            if (!Database::num_rows($res)) {
1405
                return $anonymousPath;
1406
            }
1407
            $user = Database::fetch_array($res);
1408
        } else {
1409
            $user = $userInfo;
1410
        }
1411
1412
        $pictureFilename = trim($user['picture_uri']);
1413
1414
        $dir = self::getUserPathById($id, $type);
1415
1416
        return array(
1417
            'dir' => $dir,
1418
            'file' => $pictureFilename,
1419
            'email' => $user['email'],
1420
        );
1421
    }
1422
1423
    /**
1424
     * Get user path from user ID (returns an array).
1425
     * The return format is a complete path to a folder ending with "/"
1426
     * In case the first level of subdirectory of users/ does not exist, the
1427
     * function will attempt to create it. Probably not the right place to do it
1428
     * but at least it avoids headaches in many other places.
1429
     * @param   integer $id User ID
1430
     * @param   string  $type Type of path to return (can be 'system', 'web', 'rel', 'last')
1431
     * @return  string  User folder path (i.e. /var/www/chamilo/app/upload/users/1/1/)
1432
     */
1433
    public static function getUserPathById($id, $type)
1434
    {
1435
        $id = intval($id);
1436
        if (!$id) {
1437
            return null;
1438
        }
1439
1440
        $userPath = "users/$id/";
1441
        if (api_get_setting('split_users_upload_directory') === 'true') {
1442
            $userPath = 'users/'.substr((string) $id, 0, 1).'/'.$id.'/';
1443
            // In exceptional cases, on some portals, the intermediate base user
1444
            // directory might not have been created. Make sure it is before
1445
            // going further.
1446
            $rootPath = api_get_path(SYS_UPLOAD_PATH) . 'users/' . substr((string) $id, 0, 1);
1447
            if (!is_dir($rootPath)) {
1448
                $perm = api_get_permissions_for_new_directories();
1449
                try {
1450
                    mkdir($rootPath, $perm);
1451
                } catch (Exception $e) {
1452
                    error_log($e->getMessage());
1453
                }
1454
            }
1455
        }
1456
        switch ($type) {
1457
            case 'system': // Base: absolute system path.
1458
                $userPath = api_get_path(SYS_UPLOAD_PATH).$userPath;
1459
                break;
1460
            case 'web': // Base: absolute web path.
1461
                $userPath = api_get_path(WEB_UPLOAD_PATH).$userPath;
1462
                break;
1463
            case 'rel': // Relative to the document root (e.g. app/upload/users/1/13/)
1464
                $userPath = api_get_path(REL_UPLOAD_PATH).$userPath;
1465
                break;
1466
            case 'last': // Only the last part starting with users/
1467
                break;
1468
        }
1469
1470
        return $userPath;
1471
    }
1472
1473
    /**
1474
     * Gets the current user image
1475
     * @param string $user_id
1476
     * @param int $size it can be USER_IMAGE_SIZE_SMALL,
1477
     * USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1478
     * @param bool $addRandomId
1479
     * @param array $userInfo to avoid query the DB
1480
     *
1481
     * @return string
1482
     */
1483
    public static function getUserPicture(
1484
        $user_id,
1485
        $size = USER_IMAGE_SIZE_MEDIUM,
1486
        $addRandomId = true,
1487
        $userInfo = []
1488
    ) {
1489
        $imageWebPath = self::get_user_picture_path_by_id($user_id, 'web', $userInfo);
1490
        $pictureWebFile = $imageWebPath['file'];
1491
        $pictureWebDir = $imageWebPath['dir'];
1492
1493
        $pictureAnonymousSize = '128';
1494
        $gravatarSize = 22;
1495
        $realSizeName = 'small_';
1496
1497
        switch ($size) {
1498
            case USER_IMAGE_SIZE_SMALL:
1499
                $pictureAnonymousSize = '22';
1500
                $realSizeName = 'small_';
1501
                $gravatarSize = 22;
1502
                break;
1503
            case USER_IMAGE_SIZE_MEDIUM:
1504
                $pictureAnonymousSize = '64';
1505
                $realSizeName = 'medium_';
1506
                $gravatarSize = 50;
1507
                break;
1508
            case USER_IMAGE_SIZE_ORIGINAL:
1509
                $pictureAnonymousSize = '128';
1510
                $realSizeName = '';
1511
                $gravatarSize = 108;
1512
                break;
1513
            case USER_IMAGE_SIZE_BIG:
1514
                $pictureAnonymousSize = '128';
1515
                $realSizeName = 'big_';
1516
                $gravatarSize = 200;
1517
                break;
1518
        }
1519
1520
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1521
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1522
1523
        if ($pictureWebFile == 'unknown.jpg' || empty($pictureWebFile)) {
1524
1525
            if ($gravatarEnabled === 'true') {
1526
                $file = self::getGravatar(
1527
                    $imageWebPath['email'],
1528
                    $gravatarSize,
1529
                    api_get_setting('gravatar_type')
1530
                );
1531
1532
                if ($addRandomId) {
1533
                    $file .= '&rand='.uniqid();
1534
                }
1535
1536
                return $file;
1537
            }
1538
1539
            return $anonymousPath;
1540
        }
1541
1542
        $pictureSysPath = self::get_user_picture_path_by_id($user_id, 'system');
1543
1544
        $file = $pictureSysPath['dir'].$realSizeName.$pictureWebFile;
1545
        $picture = '';
1546
        if (file_exists($file)) {
1547
            $picture = $pictureWebDir.$realSizeName.$pictureWebFile;
1548
        } else {
1549
            $file = $pictureSysPath['dir'].$pictureWebFile;
1550
            if (file_exists($file) && !is_dir($file)) {
1551
                $picture = $pictureWebFile['dir'].$pictureWebFile;
1552
            }
1553
        }
1554
1555
        if (empty($picture)) {
1556
            return $anonymousPath;
1557
        }
1558
1559
        if ($addRandomId) {
1560
            $picture .= '?rand='.uniqid();
1561
        }
1562
1563
        return $picture;
1564
    }
1565
1566
    /**
1567
     * Creates new user photos in various sizes of a user, or deletes user photos.
1568
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
1569
     * @param   int $user_id The user internal identification number.
1570
     * @param   string $file The common file name for the newly created photos.
1571
     *                       It will be checked and modified for compatibility with the file system.
1572
     *                       If full name is provided, path component is ignored.
1573
     *                       If an empty name is provided, then old user photos are deleted only,
1574
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1575
     * @param   string $source_file The full system name of the image from which user photos will be created.
1576
     * @param   string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1577
     * @return  string/bool Returns the resulting common file name of created images which usually should be stored in database.
0 ignored issues
show
Documentation introduced by
The doc-type string/bool could not be parsed: Unknown type name "string/bool" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1578
     * When deletion is requested returns empty string. In case of internal error or negative validation returns FALSE.
1579
     */
1580
    public static function update_user_picture($user_id, $file = null, $source_file = null, $cropParameters)
1581
    {
1582
        if (empty($user_id)) {
1583
            return false;
1584
        }
1585
        $delete = empty($file);
1586
        if (empty($source_file)) {
1587
            $source_file = $file;
1588
        }
1589
1590
        // User-reserved directory where photos have to be placed.
1591
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1592
1593
        $path = $path_info['dir'];
1594
        // If this directory does not exist - we create it.
1595
        if (!file_exists($path)) {
1596
            mkdir($path, api_get_permissions_for_new_directories(), true);
1597
        }
1598
1599
        // The old photos (if any).
1600
        $old_file = $path_info['file'];
1601
1602
        // Let us delete them.
1603 View Code Duplication
        if (!empty($old_file)) {
1604
            if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE) {
1605
                $prefix = 'saved_'.date('Y_m_d_H_i_s').'_'.uniqid('').'_';
1606
                @rename($path.'small_'.$old_file, $path.$prefix.'small_'.$old_file);
1607
                @rename($path.'medium_'.$old_file, $path.$prefix.'medium_'.$old_file);
1608
                @rename($path.'big_'.$old_file, $path.$prefix.'big_'.$old_file);
1609
                @rename($path.$old_file, $path.$prefix.$old_file);
1610
            } else {
1611
                @unlink($path.'small_'.$old_file);
1612
                @unlink($path.'medium_'.$old_file);
1613
                @unlink($path.'big_'.$old_file);
1614
                @unlink($path.$old_file);
1615
            }
1616
        }
1617
1618
        // Exit if only deletion has been requested. Return an empty picture name.
1619
        if ($delete) {
1620
            return '';
1621
        }
1622
1623
        // Validation 2.
1624
        $allowed_types = api_get_supported_image_extensions();
1625
        $file = str_replace('\\', '/', $file);
1626
        $filename = (($pos = strrpos($file, '/')) !== false) ? substr($file, $pos + 1) : $file;
1627
        $extension = strtolower(substr(strrchr($filename, '.'), 1));
1628
        if (!in_array($extension, $allowed_types)) {
1629
            return false;
1630
        }
1631
1632
        // This is the common name for the new photos.
1633 View Code Duplication
        if (KEEP_THE_NAME_WHEN_CHANGE_IMAGE && !empty($old_file)) {
1634
            $old_extension = strtolower(substr(strrchr($old_file, '.'), 1));
1635
            $filename = in_array($old_extension, $allowed_types) ? substr($old_file, 0, -strlen($old_extension)) : $old_file;
1636
            $filename = (substr($filename, -1) == '.') ? $filename.$extension : $filename.'.'.$extension;
1637
        } else {
1638
            $filename = api_replace_dangerous_char($filename);
1639
            if (PREFIX_IMAGE_FILENAME_WITH_UID) {
1640
                $filename = uniqid('').'_'.$filename;
1641
            }
1642
            // We always prefix user photos with user ids, so on setting
1643
            // api_get_setting('split_users_upload_directory') === 'true'
1644
            // the correspondent directories to be found successfully.
1645
            $filename = $user_id.'_'.$filename;
1646
        }
1647
1648
        //Crop the image to adjust 1:1 ratio
1649
        $image = new Image($source_file);
1650
        $image->crop($cropParameters);
1651
1652
        // Storing the new photos in 4 versions with various sizes.
1653
1654
        $small = new Image($source_file);
1655
        $small->resize(22);
1656
        $small->send_image($path.'small_'.$filename);
1657
        $medium = new Image($source_file);
1658
        $medium->resize(85);
1659
        $medium->send_image($path.'medium_'.$filename);
1660
        $normal = new Image($source_file);
1661
        $normal->resize(200);
1662
        $normal->send_image($path.$filename);
1663
1664
        $big = new Image($source_file); // This is the original picture.
1665
        $big->send_image($path.'big_'.$filename);
1666
1667
        $result = $small && $medium && $normal && $big;
1668
1669
        return $result ? $filename : false;
1670
    }
1671
1672
    /**
1673
     * Update User extra field file type into {user_folder}/{$extra_field}
1674
     * @param int $user_id          The user internal identification number
1675
     * @param string $extra_field   The $extra_field The extra field name
1676
     * @param null $file            The filename
1677
     * @param null $source_file     The temporal filename
1678
     * @return bool|null            return filename if success, but false
1679
     */
1680
    public static function update_user_extra_file($user_id, $extra_field = '', $file = null, $source_file = null)
1681
    {
1682
        // Add Filter
1683
        $source_file = Security::filter_filename($source_file);
1684
        $file = Security::filter_filename($file);
1685
1686
        if (empty($user_id)) {
1687
            return false;
1688
        }
1689
1690
        if (empty($source_file)) {
1691
            $source_file = $file;
1692
        }
1693
1694
        // User-reserved directory where extra file have to be placed.
1695
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1696
        $path = $path_info['dir'];
1697
        if (!empty($extra_field)) {
1698
            $path .= $extra_field . '/';
1699
        }
1700
        // If this directory does not exist - we create it.
1701
        if (!file_exists($path)) {
1702
            @mkdir($path, api_get_permissions_for_new_directories(), true);
1703
        }
1704
1705
        if (filter_extension($file)) {
1706
            if (@move_uploaded_file($source_file,$path.$file)) {
1707
                if ($extra_field) {
1708
                    return $extra_field.'/'.$file;
1709
                } else {
1710
                    return $file;
1711
                }
1712
            }
1713
        }
1714
        return false; // this should be returned if anything went wrong with the upload
1715
    }
1716
1717
1718
    /**
1719
     * Deletes user photos.
1720
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
1721
     * @param int $user_id            The user internal identitfication number.
1722
     * @return string/bool            Returns empty string on success, FALSE on error.
0 ignored issues
show
Documentation introduced by
The doc-type string/bool could not be parsed: Unknown type name "string/bool" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1723
     */
1724
    public static function delete_user_picture($user_id)
1725
    {
1726
        return self::update_user_picture($user_id);
0 ignored issues
show
Bug introduced by
The call to update_user_picture() misses a required argument $cropParameters.

This check looks for function calls that miss required arguments.

Loading history...
1727
    }
1728
1729
    /**
1730
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
1731
     * doesn't have any.
1732
     *
1733
     * If there has been a request to remove a production, the function will return
1734
     * without building the list unless forced to do so by the optional second
1735
     * parameter. This increases performance by avoiding to read through the
1736
     * productions on the filesystem before the removal request has been carried
1737
     * out because they'll have to be re-read afterwards anyway.
1738
     *
1739
     * @param    int $user_id    User id
1740
     * @param    $force    Optional parameter to force building after a removal request
1741
     *
1742
     * @return    A string containing the XHTML code to dipslay the production list, or FALSE
1743
     */
1744
    public static function build_production_list($user_id, $force = false, $showdelete = false)
1745
    {
1746
        if (!$force && !empty($_POST['remove_production'])) {
1747
            return true; // postpone reading from the filesystem
1748
        }
1749
        $productions = self::get_user_productions($user_id);
1750
1751
        if (empty($productions)) {
1752
            return false;
1753
        }
1754
1755
        $production_path = self::get_user_picture_path_by_id($user_id, 'web');
1756
        $production_dir = $production_path['dir'];
1757
        $del_image = Display::returnIconPath('delete.png');
1758
        $add_image = Display::returnIconPath('archive.png');
1759
        $del_text = get_lang('Delete');
1760
        $production_list = '';
1761
        if (count($productions) > 0) {
1762
            $production_list = '<div class="files-production"><ul id="productions">';
1763
            foreach ($productions as $file) {
1764
                $production_list .= '<li><img src="'.$add_image.'" /><a href="'.$production_dir.urlencode($file).'" target="_blank">'.htmlentities($file).'</a>';
1765 View Code Duplication
                if ($showdelete) {
1766
                    $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>';
1767
                }
1768
            }
1769
            $production_list .= '</ul></div>';
1770
        }
1771
1772
        return $production_list;
1773
    }
1774
1775
    /**
1776
     * Returns an array with the user's productions.
1777
     *
1778
     * @param    $user_id    User id
1779
     * @return   array  An array containing the user's productions
1780
     */
1781
    public static function get_user_productions($user_id)
1782
    {
1783
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
1784
        $production_repository = $production_path['dir'];
1785
        $productions = array();
1786
1787
        if (is_dir($production_repository)) {
1788
            $handle = opendir($production_repository);
1789
            while ($file = readdir($handle)) {
1790
                if ($file == '.' ||
1791
                    $file == '..' ||
1792
                    $file == '.htaccess' ||
1793
                    is_dir($production_repository.$file)
1794
                ) {
1795
                    // skip current/parent directory and .htaccess
1796
                    continue;
1797
                }
1798
1799
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
1800
                    // User's photos should not be listed as productions.
1801
                    continue;
1802
                }
1803
                $productions[] = $file;
1804
            }
1805
        }
1806
1807
        return $productions;
1808
    }
1809
1810
    /**
1811
     * Remove a user production.
1812
     *
1813
     * @param int $user_id        User id
1814
     * @param string $production    The production to remove
1815
     */
1816
    public static function remove_user_production($user_id, $production)
1817
    {
1818
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
1819
        $production_file = $production_path['dir'].$production;
1820
        if (is_file($production_file)) {
1821
            unlink($production_file);
1822
            return true;
1823
        }
1824
        return false;
1825
    }
1826
1827
    /**
1828
     * Update an extra field value for a given user
1829
     * @param    integer   $userId User ID
1830
     * @param    string    $variable Field variable name
1831
     * @param    string    $value Field value
1832
     *
1833
     * @return    boolean    true if field updated, false otherwise
1834
     */
1835 View Code Duplication
    public static function update_extra_field_value($userId, $variable, $value = '')
1836
    {
1837
        $extraFieldValue = new ExtraFieldValue('user');
1838
        $params = [
1839
            'item_id' => $userId,
1840
            'variable' => $variable,
1841
            'value' => $value
1842
        ];
1843
        return $extraFieldValue->save($params);
1844
    }
1845
1846
    /**
1847
     * Get an array of extra fields with field details (type, default value and options)
1848
     * @param    integer    Offset (from which row)
1849
     * @param    integer    Number of items
1850
     * @param    integer    Column on which sorting is made
1851
     * @param    string    Sorting direction
1852
     * @param    boolean    Optional. Whether we get all the fields or just the visible ones
1853
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
1854
     * @return    array    Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
1855
     */
1856
    public static function get_extra_fields(
1857
        $from = 0,
1858
        $number_of_items = 0,
1859
        $column = 5,
1860
        $direction = 'ASC',
1861
        $all_visibility = true,
1862
        $field_filter = null
1863
    ) {
1864
        $fields = array();
1865
        $t_uf = Database :: get_main_table(TABLE_EXTRA_FIELD);
1866
        $t_ufo = Database :: get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
1867
        $columns = array(
1868
            'id',
1869
            'variable',
1870
            'field_type',
1871
            'display_text',
1872
            'default_value',
1873
            'field_order',
1874
            'filter'
1875
        );
1876
        $column = intval($column);
1877
        $sort_direction = '';
1878
        if (in_array(strtoupper($direction), array('ASC', 'DESC'))) {
1879
            $sort_direction = strtoupper($direction);
1880
        }
1881
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1882
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
1883
        if (!$all_visibility) {
1884
            $sqlf .= " AND visible = 1 ";
1885
        }
1886
        if (!is_null($field_filter)) {
1887
            $field_filter = intval($field_filter);
1888
            $sqlf .= " AND filter = $field_filter ";
1889
        }
1890
        $sqlf .= " ORDER BY ".$columns[$column]." $sort_direction ";
1891
        if ($number_of_items != 0) {
1892
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
1893
        }
1894
        $resf = Database::query($sqlf);
1895
        if (Database::num_rows($resf) > 0) {
1896
            while ($rowf = Database::fetch_array($resf)) {
1897
                $fields[$rowf['id']] = array(
1898
                    0 => $rowf['id'],
1899
                    1 => $rowf['variable'],
1900
                    2 => $rowf['field_type'],
1901
                    3 => (empty($rowf['display_text']) ? '' : $rowf['display_text']),
1902
                    4 => $rowf['default_value'],
1903
                    5 => $rowf['field_order'],
1904
                    6 => $rowf['visible'],
1905
                    7 => $rowf['changeable'],
1906
                    8 => $rowf['filter'],
1907
                    9 => array(),
1908
                    10 => '<a name="'.$rowf['id'].'"></a>',
1909
                );
1910
1911
                $sqlo = "SELECT * FROM $t_ufo
1912
                         WHERE field_id = ".$rowf['id']."
1913
                         ORDER BY option_order ASC";
1914
                $reso = Database::query($sqlo);
1915
                if (Database::num_rows($reso) > 0) {
1916
                    while ($rowo = Database::fetch_array($reso)) {
1917
                        $fields[$rowf['id']][9][$rowo['id']] = array(
1918
                            0 => $rowo['id'],
1919
                            1 => $rowo['option_value'],
1920
                            2 => (empty($rowo['display_text']) ? '' : $rowo['display_text']),
1921
                            3 => $rowo['option_order']
1922
                        );
1923
                    }
1924
                }
1925
            }
1926
        }
1927
1928
        return $fields;
1929
    }
1930
1931
    /**
1932
     * Build a list of extra file already uploaded in $user_folder/{$extra_field}/
1933
     * @param $user_id
1934
     * @param $extra_field
1935
     * @param bool $force
1936
     * @param bool $showdelete
1937
     * @return bool|string
1938
     */
1939
    public static function build_user_extra_file_list($user_id, $extra_field, $force = false, $showdelete = false)
1940
    {
1941
        if (!$force && !empty($_POST['remove_'.$extra_field])) {
1942
            return true; // postpone reading from the filesystem
1943
        }
1944
1945
        $extra_files = self::get_user_extra_files($user_id, $extra_field);
1946
        if (empty($extra_files)) {
1947
            return false;
1948
        }
1949
1950
        $path_info = self::get_user_picture_path_by_id($user_id, 'web');
1951
        $path = $path_info['dir'];
1952
        $del_image = Display::returnIconPath('delete.png');
1953
1954
        $del_text = get_lang('Delete');
1955
        $extra_file_list = '';
1956
        if (count($extra_files) > 0) {
1957
            $extra_file_list = '<div class="files-production"><ul id="productions">';
1958
            foreach ($extra_files as $file) {
1959
                $filename = substr($file,strlen($extra_field)+1);
1960
                $extra_file_list .= '<li>'.Display::return_icon('archive.png').'<a href="'.$path.$extra_field.'/'.urlencode($filename).'" target="_blank">'.htmlentities($filename).'</a> ';
1961 View Code Duplication
                if ($showdelete) {
1962
                    $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>';
1963
                }
1964
            }
1965
            $extra_file_list .= '</ul></div>';
1966
        }
1967
1968
        return $extra_file_list;
1969
    }
1970
1971
    /**
1972
     * Get valid filenames in $user_folder/{$extra_field}/
1973
     * @param $user_id
1974
     * @param $extra_field
1975
     * @param bool $full_path
1976
     * @return array
1977
     */
1978
    public static function get_user_extra_files($user_id, $extra_field, $full_path = false)
1979
    {
1980
        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...
1981
            // Nothing to do
1982
        } else {
1983
            $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1984
            $path = $path_info['dir'];
1985
        }
1986
        $extra_data = self::get_extra_user_data_by_field($user_id, $extra_field);
1987
        $extra_files = $extra_data[$extra_field];
1988
        if (is_array($extra_files)) {
1989
            foreach ($extra_files as $key => $value) {
1990
                if (!$full_path) {
1991
                    // Relative path from user folder
1992
                    $files[] = $value;
1993
                } else {
1994
                    $files[] = $path.$value;
1995
                }
1996
            }
1997
        } elseif (!empty($extra_files)) {
1998
            if (!$full_path) {
1999
                // Relative path from user folder
2000
                $files[] = $extra_files;
2001
            } else {
2002
                $files[] = $path.$extra_files;
2003
            }
2004
        }
2005
2006
        return $files; // can be an empty array
2007
    }
2008
2009
    /**
2010
     * Remove an {$extra_file} from the user folder $user_folder/{$extra_field}/
2011
     * @param $user_id
2012
     * @param $extra_field
2013
     * @param $extra_file
2014
     * @return bool
2015
     */
2016
    public static function remove_user_extra_file($user_id, $extra_field, $extra_file)
2017
    {
2018
        $extra_file = Security::filter_filename($extra_file);
2019
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2020
        if (strpos($extra_file, $extra_field) !== false) {
2021
            $path_extra_file = $path_info['dir'].$extra_file;
2022
        } else {
2023
            $path_extra_file = $path_info['dir'].$extra_field.'/'.$extra_file;
2024
        }
2025
        if (is_file($path_extra_file)) {
2026
            unlink($path_extra_file);
2027
            return true;
2028
        }
2029
        return false;
2030
    }
2031
2032
    /**
2033
     * Creates a new extra field
2034
     * @param    string    $variable Field's internal variable name
2035
     * @param    int       $fieldType  Field's type
2036
     * @param    string    $displayText Field's language var name
2037
     * @param    string    $default Field's default value
2038
     * @return int
2039
     */
2040 View Code Duplication
    public static function create_extra_field($variable, $fieldType, $displayText, $default)
2041
    {
2042
        $extraField = new ExtraField('user');
2043
        $params = [
2044
            'variable' => $variable,
2045
            'field_type' => $fieldType,
2046
            'display_text' => $displayText,
2047
            'default_value' => $default
2048
        ];
2049
2050
        return $extraField->save($params);
2051
    }
2052
2053
    /**
2054
     * Check if a field is available
2055
     * @param    string    th$variable
2056
     * @return    boolean
2057
     */
2058
    public static function is_extra_field_available($variable)
2059
    {
2060
        $extraField = new ExtraField('user');
2061
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2062
2063
        return empty($data) ? true : false;
2064
    }
2065
2066
    /**
2067
     * Gets user extra fields data
2068
     * @param    integer    User ID
2069
     * @param    boolean    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2070
     * @param    boolean    Whether to return invisible fields as well
2071
     * @param    boolean    Whether to split multiple-selection fields or not
2072
     * @return    array    Array of fields => value for the given user
2073
     */
2074
    public static function get_extra_user_data(
2075
        $user_id,
2076
        $prefix = false,
2077
        $all_visibility = true,
2078
        $splitmultiple = false,
2079
        $field_filter = null
2080
    ) {
2081
        // A sanity check.
2082 View Code Duplication
        if (empty($user_id)) {
2083
            $user_id = 0;
2084
        } else {
2085
            if ($user_id != strval(intval($user_id)))
2086
                return array();
2087
        }
2088
        $extra_data = array();
2089
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2090
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2091
        $user_id = intval($user_id);
2092
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2093
                FROM $t_uf f
2094
                WHERE
2095
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2096
                ";
2097
        $filter_cond = '';
2098
2099
        if (!$all_visibility) {
2100
            if (isset($field_filter)) {
2101
                $field_filter = intval($field_filter);
2102
                $filter_cond .= " AND filter = $field_filter ";
2103
            }
2104
            $sql .= " AND f.visible = 1 $filter_cond ";
2105
        } else {
2106
            if (isset($field_filter)) {
2107
                $field_filter = intval($field_filter);
2108
                $sql .= " AND filter = $field_filter ";
2109
            }
2110
        }
2111
2112
        $sql .= " ORDER BY f.field_order";
2113
2114
        $res = Database::query($sql);
2115
        if (Database::num_rows($res) > 0) {
2116
            while ($row = Database::fetch_array($res)) {
2117
                if ($row['type'] == self::USER_FIELD_TYPE_TAG) {
2118
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2119
                    $extra_data['extra_'.$row['fvar']] = $tags;
2120
                } else {
2121
                    $sqlu = "SELECT value as fval
2122
                            FROM $t_ufv
2123
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2124
                    $resu = Database::query($sqlu);
2125
                    // get default value
2126
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2127
                               WHERE id=".$row['id'];
2128
                    $res_df = Database::query($sql_df);
2129
2130
                    if (Database::num_rows($resu) > 0) {
2131
                        $rowu = Database::fetch_array($resu);
2132
                        $fval = $rowu['fval'];
2133
                        if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2134
                            $fval = explode(';', $rowu['fval']);
2135
                        }
2136
                    } else {
2137
                        $row_df = Database::fetch_array($res_df);
2138
                        $fval = $row_df['fval_df'];
2139
                    }
2140
                    // We get here (and fill the $extra_data array) even if there
2141
                    // is no user with data (we fill it with default values)
2142
                    if ($prefix) {
2143 View Code Duplication
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2144
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2145
                        } else {
2146
                            $extra_data['extra_'.$row['fvar']] = $fval;
2147
                        }
2148 View Code Duplication
                    } else {
2149
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2150
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2151
                        } else {
2152
                            $extra_data[$row['fvar']] = $fval;
2153
                        }
2154
                    }
2155
                }
2156
            }
2157
        }
2158
2159
        return $extra_data;
2160
    }
2161
2162
    /** Get extra user data by field
2163
     * @param int    user ID
2164
     * @param string the internal variable name of the field
2165
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2166
     */
2167
    public static function get_extra_user_data_by_field(
2168
        $user_id,
2169
        $field_variable,
2170
        $prefix = false,
2171
        $all_visibility = true,
2172
        $splitmultiple = false
2173
    ) {
2174
        // A sanity check.
2175 View Code Duplication
        if (empty($user_id)) {
2176
            $user_id = 0;
2177
        } else {
2178
            if ($user_id != strval(intval($user_id)))
2179
                return array();
2180
        }
2181
        $extra_data = array();
2182
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2183
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2184
        $user_id = intval($user_id);
2185
2186
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2187
                FROM $t_uf f
2188
                WHERE f.variable = '$field_variable' ";
2189
2190
        if (!$all_visibility) {
2191
            $sql .= " AND f.visible = 1 ";
2192
        }
2193
2194
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2195
2196
        $sql .= " ORDER BY f.field_order";
2197
2198
        $res = Database::query($sql);
2199
        if (Database::num_rows($res) > 0) {
2200
            while ($row = Database::fetch_array($res)) {
2201
                $sqlu = "SELECT value as fval FROM $t_ufv v INNER JOIN $t_uf f
2202
                         ON (v.field_id = f.id)
2203
                         WHERE
2204
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2205
                            field_id = ".$row['id']." AND
2206
                            item_id = ".$user_id;
2207
                $resu = Database::query($sqlu);
2208
                $fval = '';
2209
                if (Database::num_rows($resu) > 0) {
2210
                    $rowu = Database::fetch_array($resu);
2211
                    $fval = $rowu['fval'];
2212
                    if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2213
                        $fval = explode(';', $rowu['fval']);
2214
                    }
2215
                }
2216
                if ($prefix) {
2217
                    $extra_data['extra_'.$row['fvar']] = $fval;
2218
                } else {
2219
                    $extra_data[$row['fvar']] = $fval;
2220
                }
2221
            }
2222
        }
2223
2224
        return $extra_data;
2225
    }
2226
2227
    /**
2228
     * Get the extra field information for a certain field (the options as well)
2229
     * @param  int     $variable The name of the field we want to know everything about
2230
     * @return array   Array containing all the information about the extra profile field
2231
     * (first level of array contains field details, then 'options' sub-array contains options details,
2232
     * as returned by the database)
2233
     * @author Julio Montoya
2234
     * @since v1.8.6
2235
     */
2236
    public static function get_extra_field_information_by_name($variable)
2237
    {
2238
        $extraField = new ExtraField('user');
2239
2240
        return $extraField->get_handler_field_info_by_field_variable($variable);
2241
    }
2242
2243
    /**
2244
     * @param string $type
2245
     *
2246
     * @return array
2247
     */
2248
    public static function get_all_extra_field_by_type($type)
2249
    {
2250
        $extraField = new ExtraField('user');
2251
2252
        return $extraField->get_all_extra_field_by_type($type);
2253
    }
2254
2255
    /**
2256
     * Get all the extra field information of a certain field (also the options)
2257
     *
2258
     * @param int $field_name the name of the field we want to know everything of
0 ignored issues
show
Bug introduced by
There is no parameter named $field_name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2259
     * @return array $return containing all th information about the extra profile field
2260
     * @author Julio Montoya
2261
     * @deprecated
2262
     * @since v1.8.6
2263
     */
2264
    public static function get_extra_field_information($fieldId)
2265
    {
2266
        $extraField = new ExtraField('user');
2267
2268
        return $extraField->getFieldInfoByFieldId($fieldId);
2269
    }
2270
2271
    /** Get extra user data by value
2272
     * @param string the internal variable name of the field
2273
     * @param string the internal value of the field
2274
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2275
     */
2276
    public static function get_extra_user_data_by_value($field_variable, $field_value, $all_visibility = true)
2277
    {
2278
        $extraField = new ExtraFieldValue('user');
2279
2280
        $data = $extraField->get_values_by_handler_and_field_variable(
2281
            $field_variable,
2282
            $field_value,
2283
            null,
2284
            true,
2285
            intval($all_visibility)
2286
        );
2287
2288
        $result = [];
2289
        if (!empty($data)) {
2290
            foreach ($data as $data) {
2291
                $result[] = $data['item_id'];
2292
            }
2293
        }
2294
2295
        return $result;
2296
    }
2297
2298
    /**
2299
     * Get extra user data by field variable
2300
     * @param string    field variable
2301
     * @return array    data
2302
     */
2303
    public static function get_extra_user_data_by_field_variable($field_variable)
2304
    {
2305
        $extra_information_by_variable = self::get_extra_field_information_by_name($field_variable);
2306
        $field_id = intval($extra_information_by_variable['id']);
2307
2308
        $extraField = new ExtraFieldValue('user');
2309
        $data = $extraField->getValuesByFieldId($field_id);
2310
2311
        if (!empty($data) > 0) {
2312
            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...
2313
                $user_id = $row['item_id'];
2314
                $data[$user_id] = $row;
2315
            }
2316
        }
2317
2318
        return $data;
2319
    }
2320
2321
    /**
2322
     * Gives a list of [session_category][session_id] for the current user.
2323
     * @param integer $user_id
2324
     * @param boolean whether to fill the first element or not (to give space for courses out of categories)
2325
     * @param boolean  optional true if limit time from session is over, false otherwise
2326
     * @param boolean $ignoreTimeLimit ignore time start/end
2327
     * @return array  list of statuses [session_category][session_id]
2328
     *
2329
     * @todo ensure multiple access urls are managed correctly
2330
     */
2331
    public static function get_sessions_by_category(
2332
        $user_id,
2333
        $is_time_over = true,
2334
        $ignore_visibility_for_admins = false,
2335
        $ignoreTimeLimit = false
2336
    ) {
2337
        // Database Table Definitions
2338
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2339
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2340
        $tbl_session_category = Database :: get_main_table(TABLE_MAIN_SESSION_CATEGORY);
2341
2342
        if ($user_id != strval(intval($user_id))) {
2343
            return array();
2344
        }
2345
2346
        // Get the list of sessions per user
2347
        $now = api_get_utc_datetime();
2348
2349
        $sql = "SELECT DISTINCT
2350
                    session.id,
2351
                    session.name,
2352
                    session.access_start_date,
2353
                    session.access_end_date,
2354
                    session_category_id,
2355
                    session_category.name as session_category_name,
2356
                    session_category.date_start session_category_date_start,
2357
                    session_category.date_end session_category_date_end,
2358
                    coach_access_start_date,
2359
                    coach_access_end_date
2360
              FROM $tbl_session as session
2361
                  LEFT JOIN $tbl_session_category session_category
2362
                  ON (session_category_id = session_category.id)
2363
                  LEFT JOIN $tbl_session_course_user as session_rel_course_user
2364
                  ON (session_rel_course_user.session_id = session.id)
2365
              WHERE (
2366
                    session_rel_course_user.user_id = $user_id OR
2367
                    session.id_coach = $user_id
2368
              )
2369
              ORDER BY session_category_name, name";
2370
2371
        $result = Database::query($sql);
2372
        $categories = array();
2373
        if (Database::num_rows($result) > 0) {
2374
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2375
2376
                // User portal filters:
2377
                if ($ignoreTimeLimit == false) {
2378
                    if ($is_time_over) {
2379
                        // History
2380
                        if (empty($row['access_end_date']) || $row['access_end_date'] == '0000-00-00 00:00:00') {
2381
                            continue;
2382
                        }
2383
2384
                        if (isset($row['access_end_date'])) {
2385
                            if ($row['access_end_date'] > $now) {
2386
                                continue;
2387
                            }
2388
2389
                        }
2390
                    } else {
2391
                        // Current user portal
2392
                        if (api_is_allowed_to_create_course()) {
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...
2393
                            // Teachers can access the session depending in the access_coach date
2394
                        } else {
2395
                            if (isset($row['access_end_date']) &&
2396
                                ($row['access_end_date'] != '0000-00-00 00:00:00') &&
2397
                                !empty($row['access_end_date'])
2398
                            ) {
2399
                                if ($row['access_end_date'] <= $now) {
2400
                                    continue;
2401
                                }
2402
                            }
2403
                        }
2404
                    }
2405
                }
2406
2407
                $categories[$row['session_category_id']]['session_category'] = array(
2408
                    'id' => $row['session_category_id'],
2409
                    'name' => $row['session_category_name'],
2410
                    'date_start' => $row['session_category_date_start'],
2411
                    'date_end' => $row['session_category_date_end']
2412
                );
2413
2414
                $session_id = $row['id'];
2415
2416
                $courseList = UserManager::get_courses_list_by_session(
2417
                    $user_id,
2418
                    $row['id']
2419
                );
2420
2421
                // Session visibility.
2422
                $visibility = api_get_session_visibility(
2423
                    $session_id,
2424
                    null,
2425
                    $ignore_visibility_for_admins
2426
                );
2427
2428
2429
                // Course Coach session visibility.
2430
                $blockedCourseCount = 0;
2431
                $closedVisibilityList = array(
2432
                    COURSE_VISIBILITY_CLOSED,
2433
                    COURSE_VISIBILITY_HIDDEN
2434
                );
2435
2436
                foreach ($courseList as $course) {
2437
                    // Checking session visibility
2438
                    $visibility = api_get_session_visibility(
2439
                        $session_id,
2440
                        $course['real_id'],
2441
                        $ignore_visibility_for_admins
2442
                    );
2443
2444
                    $courseIsVisible = !in_array($course['visibility'], $closedVisibilityList);
2445
                    if ($courseIsVisible == false || $visibility == SESSION_INVISIBLE) {
2446
                        $blockedCourseCount++;
2447
                    }
2448
                }
2449
2450
                // If all courses are blocked then no show in the list.
2451
                if ($blockedCourseCount == count($courseList)) {
2452
                    $visibility = SESSION_INVISIBLE;
2453
                }
2454
2455
                switch ($visibility) {
2456
                    case SESSION_VISIBLE_READ_ONLY:
2457
                    case SESSION_VISIBLE:
2458
                    case SESSION_AVAILABLE:
2459
                        break;
2460
                    case SESSION_INVISIBLE:
2461
                        if ($ignore_visibility_for_admins == false) {
2462
                            continue(2);
2463
                        }
2464
                }
2465
2466
                $categories[$row['session_category_id']]['sessions'][$row['id']] = array(
2467
                    'session_name' => $row['name'],
2468
                    'session_id' => $row['id'],
2469
                    'access_start_date' => api_get_local_time($row['access_start_date']),
2470
                    'access_end_date' => api_get_local_time($row['access_end_date']),
2471
                    'coach_access_start_date' => api_get_local_time($row['coach_access_start_date']),
2472
                    'coach_access_end_date' => api_get_local_time($row['coach_access_end_date']),
2473
                    'courses' => $courseList
2474
                );
2475
            }
2476
        }
2477
2478
        return $categories;
2479
    }
2480
2481
    /**
2482
     * Gives a list of [session_id-course_code] => [status] for the current user.
2483
     * @param integer $user_id
2484
     * @return array  list of statuses (session_id-course_code => status)
2485
     */
2486
    public static function get_personal_session_course_list($user_id)
2487
    {
2488
        // Database Table Definitions
2489
        $tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE);
2490
        $tbl_user = Database :: get_main_table(TABLE_MAIN_USER);
2491
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2492
        $tbl_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
2493
        $tbl_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
2494
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2495
2496
        if ($user_id != strval(intval($user_id))) {
2497
            return array();
2498
        }
2499
2500
        // We filter the courses from the URL
2501
        $join_access_url = $where_access_url = '';
2502
2503
        if (api_get_multiple_access_url()) {
2504
            $access_url_id = api_get_current_access_url_id();
2505
            if ($access_url_id != -1) {
2506
                $tbl_url_course = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2507
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2508
                $where_access_url = " AND access_url_id = $access_url_id ";
2509
            }
2510
        }
2511
2512
        // Courses in which we subscribed out of any session
2513
        $tbl_user_course_category = Database :: get_main_table(TABLE_USER_COURSE_CATEGORY);
2514
2515
        $sql = "SELECT
2516
                    course.code,
2517
                    course_rel_user.status course_rel_status,
2518
                    course_rel_user.sort sort,
2519
                    course_rel_user.user_course_cat user_course_cat
2520
                 FROM ".$tbl_course_user." course_rel_user
2521
                 LEFT JOIN ".$tbl_course." course
2522
                 ON course.id = course_rel_user.c_id
2523
                 LEFT JOIN ".$tbl_user_course_category." user_course_category
2524
                 ON course_rel_user.user_course_cat = user_course_category.id
2525
                 $join_access_url
2526
                 WHERE
2527
                    course_rel_user.user_id = '".$user_id."' AND
2528
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2529
                    $where_access_url
2530
                 ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
2531
2532
        $course_list_sql_result = Database::query($sql);
2533
2534
        $personal_course_list = array();
2535
        if (Database::num_rows($course_list_sql_result) > 0) {
2536
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2537
                $course_info = api_get_course_info($result_row['code']);
2538
                $result_row['course_info'] = $course_info;
2539
                $personal_course_list[] = $result_row;
2540
            }
2541
        }
2542
2543
        $coachCourseConditions = null;
2544
2545
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2546
2547 View Code Duplication
        if (api_is_allowed_to_create_course()) {
2548
            $sessionListFromCourseCoach = array();
2549
            $sql =" SELECT DISTINCT session_id
2550
                    FROM $tbl_session_course_user
2551
                    WHERE user_id = $user_id AND status = 2 ";
2552
2553
            $result = Database::query($sql);
2554
            if (Database::num_rows($result)) {
2555
                $result = Database::store_result($result);
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, store_result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2556
                foreach ($result as $session) {
2557
                    $sessionListFromCourseCoach[]= $session['session_id'];
2558
                }
2559
            }
2560
            if (!empty($sessionListFromCourseCoach)) {
2561
                $condition = implode("','", $sessionListFromCourseCoach);
2562
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2563
            }
2564
        }
2565
2566
        // Get the list of sessions where the user is subscribed
2567
        // This is divided into two different queries
2568
        $sessions = array();
2569
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2570
                FROM $tbl_session_user, $tbl_session s
2571
                WHERE (
2572
                    session_id = s.id AND
2573
                    user_id = $user_id AND
2574
                    relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2575
                )
2576
                $coachCourseConditions
2577
                ORDER BY access_start_date, access_end_date, name";
2578
2579
        $result = Database::query($sql);
2580
        if (Database::num_rows($result)>0) {
2581
            while ($row = Database::fetch_assoc($result)) {
2582
                $sessions[$row['id']] = $row;
2583
            }
2584
        }
2585
2586
        $sql = "SELECT DISTINCT
2587
                id, name, access_start_date, access_end_date
2588
                FROM $tbl_session s
2589
                WHERE (
2590
                    id_coach = $user_id
2591
                )
2592
                $coachCourseConditions
2593
                ORDER BY access_start_date, access_end_date, name";
2594
2595
        $result = Database::query($sql);
2596
        if (Database::num_rows($result)>0) {
2597
            while ($row = Database::fetch_assoc($result)) {
2598
                if (empty($sessions[$row['id']])) {
2599
                    $sessions[$row['id']] = $row;
2600
                }
2601
            }
2602
        }
2603
2604
        if (api_is_allowed_to_create_course()) {
2605
            foreach ($sessions as $enreg) {
2606
                $session_id = $enreg['id'];
2607
                $session_visibility = api_get_session_visibility($session_id);
2608
2609
                if ($session_visibility == SESSION_INVISIBLE) {
2610
                    continue;
2611
                }
2612
2613
                // This query is horribly slow when more than a few thousand
2614
                // users and just a few sessions to which they are subscribed
2615
                $id_session = $enreg['id'];
2616
                $personal_course_list_sql = "SELECT DISTINCT
2617
                        course.code code,
2618
                        course.title i,
2619
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
2620
                        email, course.course_language l,
2621
                        1 sort,
2622
                        category_code user_course_cat,
2623
                        access_start_date,
2624
                        access_end_date,
2625
                        session.id as session_id,
2626
                        session.name as session_name
2627
                    FROM $tbl_session_course_user as session_course_user
2628
                        INNER JOIN $tbl_course AS course
2629
                            ON course.id = session_course_user.c_id
2630
                        INNER JOIN $tbl_session as session
2631
                            ON session.id = session_course_user.session_id
2632
                        LEFT JOIN $tbl_user as user
2633
                            ON user.id = session_course_user.user_id OR session.id_coach = user.id
2634
                    WHERE
2635
                        session_course_user.session_id = $id_session AND (
2636
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
2637
                            OR session.id_coach = $user_id
2638
                        )
2639
                    ORDER BY i";
2640
                $course_list_sql_result = Database::query($personal_course_list_sql);
2641
2642 View Code Duplication
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2643
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
2644
                    $key = $result_row['session_id'].' - '.$result_row['code'];
2645
                    $personal_course_list[$key] = $result_row;
2646
                }
2647
            }
2648
        }
2649
2650
        foreach ($sessions as $enreg) {
2651
            $session_id = $enreg['id'];
2652
            $session_visibility = api_get_session_visibility($session_id);
2653
            if ($session_visibility == SESSION_INVISIBLE) {
2654
                continue;
2655
            }
2656
2657
            /* This query is very similar to the above query,
2658
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
2659
            $personal_course_list_sql = "SELECT DISTINCT
2660
                course.code code,
2661
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
2662
                email,
2663
                course.course_language l,
2664
                1 sort,
2665
                category_code user_course_cat,
2666
                access_start_date,
2667
                access_end_date,
2668
                session.id as session_id,
2669
                session.name as session_name,
2670
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
2671
            FROM $tbl_session_course_user as session_course_user
2672
                INNER JOIN $tbl_course AS course
2673
                ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
2674
                INNER JOIN $tbl_session as session ON session_course_user.session_id = session.id
2675
                LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
2676
            WHERE session_course_user.user_id = $user_id
2677
            ORDER BY i";
2678
2679
            $course_list_sql_result = Database::query($personal_course_list_sql);
2680
2681 View Code Duplication
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2682
                $result_row['course_info'] = api_get_course_info($result_row['code']);
2683
                $key = $result_row['session_id'].' - '.$result_row['code'];
2684
                if (!isset($personal_course_list[$key])) {
2685
                    $personal_course_list[$key] = $result_row;
2686
                }
2687
            }
2688
        }
2689
2690
        return $personal_course_list;
2691
    }
2692
2693
    /**
2694
     * Gives a list of courses for the given user in the given session
2695
     * @param integer $user_id
2696
     * @param integer $session_id
2697
     * @return array  list of statuses (session_id-course_code => status)
2698
     */
2699
    public static function get_courses_list_by_session($user_id, $session_id)
2700
    {
2701
        // Database Table Definitions
2702
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2703
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
2704
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2705
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2706
2707
        $user_id = intval($user_id);
2708
        $session_id = intval($session_id);
2709
        //we filter the courses from the URL
2710
        $join_access_url = $where_access_url = '';
2711
2712
        if (api_get_multiple_access_url()) {
2713
            $urlId = api_get_current_access_url_id();
2714
            if ($urlId != -1) {
2715
                $tbl_url_session = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
2716
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
2717
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
2718
            }
2719
        }
2720
2721
        $personal_course_list = array();
2722
        $courses = array();
2723
2724
        /* This query is very similar to the query below, but it will check the
2725
        session_rel_course_user table if there are courses registered
2726
        to our user or not */
2727
2728
        $sql = "SELECT DISTINCT
2729
                    c.visibility,
2730
                    c.id as real_id,                    
2731
                    sc.position
2732
                FROM $tbl_session_course_user as scu
2733
                INNER JOIN $tbl_session_course sc
2734
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
2735
                INNER JOIN $tableCourse as c
2736
                ON (scu.c_id = c.id)
2737
                $join_access_url
2738
                WHERE
2739
                    scu.user_id = $user_id AND
2740
                    scu.session_id = $session_id
2741
                    $where_access_url
2742
                ORDER BY sc.position ASC";
2743
2744
        $result = Database::query($sql);
2745
2746 View Code Duplication
        if (Database::num_rows($result) > 0) {
2747
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2748
                $result_row['status'] = 5;
2749
                if (!in_array($result_row['real_id'], $courses)) {
2750
                    $personal_course_list[] = $result_row;
2751
                    $courses[] = $result_row['real_id'];
2752
                }
2753
            }
2754
        }
2755
2756
        if (api_is_allowed_to_create_course()) {
2757
            $sql = "SELECT DISTINCT
2758
                        c.visibility, 
2759
                        c.id as real_id,
2760
                        sc.position
2761
                    FROM $tbl_session_course_user as scu
2762
                    INNER JOIN $tbl_session as s
2763
                    ON (scu.session_id = s.id)
2764
                    INNER JOIN $tbl_session_course sc
2765
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
2766
                    INNER JOIN $tableCourse as c
2767
                    ON (scu.c_id = c.id)
2768
                    $join_access_url
2769
                    WHERE
2770
                      s.id = $session_id AND
2771
                      (
2772
                        (scu.user_id=$user_id AND scu.status=2) OR
2773
                        s.id_coach = $user_id
2774
                      )
2775
                    $where_access_url
2776
                    ORDER BY sc.position ASC";
2777
            $result = Database::query($sql);
2778
2779 View Code Duplication
            if (Database::num_rows($result) > 0) {
2780
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2781
                    $result_row['status'] = 2;
2782
                    if (!in_array($result_row['real_id'], $courses)) {
2783
                        $personal_course_list[] = $result_row;
2784
                        $courses[] = $result_row['real_id'];
2785
                    }
2786
                }
2787
            }
2788
        }
2789
2790
        if (api_is_drh()) {
2791
            $session_list = SessionManager::get_sessions_followed_by_drh($user_id);
2792
            $session_list = array_keys($session_list);
2793
            if (in_array($session_id, $session_list)) {
2794
                $course_list = SessionManager::get_course_list_by_session_id($session_id);
2795
                if (!empty($course_list)) {
2796
                    foreach ($course_list as $course) {
0 ignored issues
show
Bug introduced by
The expression $course_list 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...
2797
                        $personal_course_list[] = $course;
2798
                    }
2799
                }
2800
            }
2801
        } else {
2802
            //check if user is general coach for this session
2803
            $s = api_get_session_info($session_id);
2804
            if ($s['id_coach'] == $user_id) {
2805
                $course_list = SessionManager::get_course_list_by_session_id($session_id);
2806
2807
                if (!empty($course_list)) {
2808
                    foreach ($course_list as $course) {
0 ignored issues
show
Bug introduced by
The expression $course_list 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...
2809
                        if (!in_array($course['id'], $courses)) {
2810
                            $personal_course_list[] = $course;
2811
                        }
2812
                    }
2813
                }
2814
            }
2815
        }
2816
2817
        return $personal_course_list;
2818
    }
2819
2820
    /**
2821
     * Get user id from a username
2822
     * @param    string    Username
2823
     * @return    int        User ID (or false if not found)
2824
     */
2825
    public static function get_user_id_from_username($username)
2826
    {
2827
        if (empty($username)) {
2828
            return false;
2829
        }
2830
        $username = trim($username);
2831
        $username = Database::escape_string($username);
2832
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
2833
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
2834
        $res = Database::query($sql);
2835
        if ($res === false) {
2836
            return false;
2837
        }
2838
        if (Database::num_rows($res) !== 1) {
2839
            return false;
2840
        }
2841
        $row = Database::fetch_array($res);
2842
        return $row['id'];
2843
    }
2844
2845
    /**
2846
     * Get the users files upload from his share_folder
2847
     * @param    string    User ID
2848
     * @param   string  course directory
2849
     * @param   string  resourcetype: images, all
2850
     * @return    int        User ID (or false if not found)
2851
     */
2852
    public static function get_user_upload_files_by_course($user_id, $course, $resourcetype = 'all')
2853
    {
2854
        $return = '';
2855
        if (!empty($user_id) && !empty($course)) {
2856
            $user_id = intval($user_id);
2857
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
2858
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
2859
            $file_list = array();
2860
2861
            if (is_dir($path)) {
2862
                $handle = opendir($path);
2863 View Code Duplication
                while ($file = readdir($handle)) {
2864
                    if ($file == '.' || $file == '..' || $file == '.htaccess' || is_dir($path.$file)) {
2865
                        continue; // skip current/parent directory and .htaccess
2866
                    }
2867
                    $file_list[] = $file;
2868
                }
2869
                if (count($file_list) > 0) {
2870
                    $return = "<h4>$course</h4>";
2871
                    $return .= '<ul class="thumbnails">';
2872
                }
2873
                foreach ($file_list as $file) {
2874
                    if ($resourcetype == "all") {
2875
                        $return .= '<li><a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
2876
                    } elseif ($resourcetype == "images") {
2877
                        //get extension
2878
                        $ext = explode('.', $file);
2879
                        if ($ext[1] == 'jpg' || $ext[1] == 'jpeg' || $ext[1] == 'png' || $ext[1] == 'gif' || $ext[1] == 'bmp' || $ext[1] == 'tif') {
2880
                            $return .= '<li class="span2"><a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
2881
                                            <img src="'.$web_path.urlencode($file).'" ></a>
2882
                                        </li>';
2883
                        }
2884
                    }
2885
                }
2886
                if (count($file_list) > 0) {
2887
                    $return .= '</ul>';
2888
                }
2889
            }
2890
        }
2891
        return $return;
2892
    }
2893
2894
    /**
2895
     * Gets the API key (or keys) and return them into an array
2896
     * @param   int     Optional user id (defaults to the result of api_get_user_id())
2897
     * @return  array   Non-indexed array containing the list of API keys for this user, or FALSE on error
2898
     */
2899
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
2900
    {
2901
        if ($user_id != strval(intval($user_id)))
2902
            return false;
2903
        if (empty($user_id)) {
2904
            $user_id = api_get_user_id();
2905
        }
2906
        if ($user_id === false)
2907
            return false;
2908
        $service_name = Database::escape_string($api_service);
2909
        if (is_string($service_name) === false) {
2910
            return false;
2911
        }
2912
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2913
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
2914
        $res = Database::query($sql);
2915
        if ($res === false)
2916
            return false; //error during query
2917
        $num = Database::num_rows($res);
2918
        if ($num == 0)
2919
            return false;
2920
        $list = array();
2921
        while ($row = Database::fetch_array($res)) {
2922
            $list[$row['id']] = $row['api_key'];
2923
        }
2924
        return $list;
2925
    }
2926
2927
    /**
2928
     * Adds a new API key to the users' account
2929
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
2930
     * @return  boolean True on success, false on failure
2931
     */
2932
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
2933
    {
2934
        if ($user_id != strval(intval($user_id)))
2935
            return false;
2936
        if (empty($user_id)) {
2937
            $user_id = api_get_user_id();
2938
        }
2939
        if ($user_id === false)
2940
            return false;
2941
        $service_name = Database::escape_string($api_service);
2942
        if (is_string($service_name) === false) {
2943
            return false;
2944
        }
2945
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2946
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
2947
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
2948
        $res = Database::query($sql);
2949
        if ($res === false)
2950
            return false; //error during query
2951
        $num = Database::insert_id();
2952
        return ($num == 0) ? false : $num;
2953
    }
2954
2955
    /**
2956
     * Deletes an API key from the user's account
2957
     * @param   int     API key's internal ID
2958
     * @return  boolean True on success, false on failure
2959
     */
2960
    public static function delete_api_key($key_id)
2961
    {
2962
        if ($key_id != strval(intval($key_id)))
2963
            return false;
2964
        if ($key_id === false)
2965
            return false;
2966
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2967
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
2968
        $res = Database::query($sql);
2969
        if ($res === false)
2970
            return false; //error during query
2971
        $num = Database::num_rows($res);
2972
        if ($num !== 1)
2973
            return false;
2974
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
2975
        $res = Database::query($sql);
2976
        if ($res === false)
2977
            return false; //error during query
2978
        return true;
2979
    }
2980
2981
    /**
2982
     * Regenerate an API key from the user's account
2983
     * @param   int     user ID (defaults to the results of api_get_user_id())
2984
     * @param   string  API key's internal ID
2985
     * @return  int        num
2986
     */
2987
    public static function update_api_key($user_id, $api_service)
2988
    {
2989
        if ($user_id != strval(intval($user_id)))
2990
            return false;
2991
        if ($user_id === false)
2992
            return false;
2993
        $service_name = Database::escape_string($api_service);
2994
        if (is_string($service_name) === false) {
2995
            return false;
2996
        }
2997
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2998
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
2999
        $res = Database::query($sql);
3000
        $num = Database::num_rows($res);
3001
        if ($num == 1) {
3002
            $id_key = Database::fetch_array($res, 'ASSOC');
3003
            self::delete_api_key($id_key['id']);
3004
            $num = self::add_api_key($user_id, $api_service);
3005
        } elseif ($num == 0) {
3006
            $num = self::add_api_key($user_id);
3007
        }
3008
        return $num;
3009
    }
3010
3011
    /**
3012
     * @param   int     user ID (defaults to the results of api_get_user_id())
3013
     * @param   string    API key's internal ID
3014
     * @return  int    row ID, or return false if not found
3015
     */
3016
    public static function get_api_key_id($user_id, $api_service)
3017
    {
3018
        if ($user_id != strval(intval($user_id)))
3019
            return false;
3020
        if ($user_id === false)
3021
            return false;
3022
        if (empty($api_service))
3023
            return false;
3024
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3025
        $api_service = Database::escape_string($api_service);
3026
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3027
        $res = Database::query($sql);
3028
        if (Database::num_rows($res) < 1) {
3029
            return false;
3030
        }
3031
        $row = Database::fetch_array($res, 'ASSOC');
3032
        return $row['id'];
3033
    }
3034
3035
    /**
3036
     * Checks if a user_id is platform admin
3037
     * @param   int user ID
3038
     * @return  boolean True if is admin, false otherwise
3039
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3040
     */
3041
    public static function is_admin($user_id)
3042
    {
3043
        if (empty($user_id) or $user_id != strval(intval($user_id))) {
3044
            return false;
3045
        }
3046
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3047
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3048
        $res = Database::query($sql);
3049
        return Database::num_rows($res) === 1;
3050
    }
3051
3052
    /**
3053
     * Get the total count of users
3054
     * @param   int     Status of users to be counted
3055
     * @param   int     Access URL ID (optional)
3056
     * @return    mixed    Number of users or false on error
3057
     */
3058
    public static function get_number_of_users($status = 0, $access_url_id = null)
3059
    {
3060
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3061
        $t_a = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3062
        $sql = "SELECT count(*) FROM $t_u u";
3063
        $sql2 = '';
3064
        if (is_int($status) && $status > 0) {
3065
            $sql2 .= " WHERE u.status = $status ";
3066
        }
3067
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
3068
            $sql .= ", $t_a a ";
3069
            $sql2 .= " AND a.access_url_id = $access_url_id AND u.id = a.user_id ";
3070
        }
3071
        $sql = $sql.$sql2;
3072
        $res = Database::query($sql);
3073
        if (Database::num_rows($res) === 1) {
3074
            return (int) Database::result($res, 0, 0);
3075
        }
3076
        return false;
3077
    }
3078
3079
    /**
3080
     * @author Isaac flores <[email protected]>
3081
     * @param string The email administrator
3082
     * @param integer The user id
3083
     * @param string The message title
3084
     * @param string The content message
3085
     */
3086
    public static function send_message_in_outbox($email_administrator, $user_id, $title, $content)
3087
    {
3088
        $table_message = Database::get_main_table(TABLE_MESSAGE);
3089
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3090
        $title = api_utf8_decode($title);
3091
        $content = api_utf8_decode($content);
3092
        $email_administrator = Database::escape_string($email_administrator);
3093
        //message in inbox
3094
        $sql_message_outbox = 'SELECT id from '.$table_user.' WHERE email="'.$email_administrator.'" ';
3095
        //$num_row_query = Database::num_rows($sql_message_outbox);
3096
        $res_message_outbox = Database::query($sql_message_outbox);
3097
        $array_users_administrator = array();
3098
        while ($row_message_outbox = Database::fetch_array($res_message_outbox, 'ASSOC')) {
3099
            $array_users_administrator[] = $row_message_outbox['id'];
3100
        }
3101
        //allow to insert messages in outbox
3102
        for ($i = 0; $i < count($array_users_administrator); $i++) {
3103
            $sql_insert_outbox = "INSERT INTO $table_message(user_sender_id, user_receiver_id, msg_status, send_date, title, content ) ".
3104
                " VALUES (".
3105
                "'".(int) $user_id."', '".(int) ($array_users_administrator[$i])."', '4', '".api_get_utc_datetime()."','".Database::escape_string($title)."','".Database::escape_string($content)."'".
3106
                ")";
3107
            Database::query($sql_insert_outbox);
3108
        }
3109
    }
3110
3111
    /*
3112
     *
3113
     * USER TAGS
3114
     *
3115
     * Intructions to create a new user tag by Julio Montoya <[email protected]>
3116
     *
3117
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible. Called it "books" for example.
3118
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3119
     * 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
3120
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3121
     * 5. Test and enjoy.
3122
     *
3123
     */
3124
3125
    /**
3126
     * Gets the tags of a specific field_id
3127
     *
3128
     * @param int field_id
3129
     * @param string how we are going to result value in array or in a string (json)
3130
     * @return mixed
3131
     * @since Nov 2009
3132
     * @version 1.8.6.2
3133
     */
3134
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3135
    {
3136
        // database table definition
3137
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3138
        $field_id = intval($field_id);
3139
        $limit = intval($limit);
3140
        $tag = trim(Database::escape_string($tag));
3141
3142
        // all the information of the field
3143
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3144
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3145
        $result = Database::query($sql);
3146
        $return = array();
3147 View Code Duplication
        if (Database::num_rows($result) > 0) {
3148
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3149
                $return[] = array('caption' => $row['tag'], 'value' => $row['tag']);
3150
            }
3151
        }
3152
        if ($return_format == 'json') {
3153
            $return = json_encode($return);
3154
        }
3155
        return $return;
3156
    }
3157
3158
    /**
3159
     * @param int $field_id
3160
     * @param int $limit
3161
     * @return array
3162
     */
3163
    public static function get_top_tags($field_id, $limit = 100)
3164
    {
3165
        // database table definition
3166
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3167
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3168
        $field_id = intval($field_id);
3169
        $limit = intval($limit);
3170
        // all the information of the field
3171
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3172
                INNER JOIN $table_user_tag ut
3173
                ON(ut.id = uv.tag_id)
3174
                WHERE field_id = $field_id
3175
                GROUP BY tag_id
3176
                ORDER BY count DESC
3177
                LIMIT $limit";
3178
        $result = Database::query($sql);
3179
        $return = array();
3180
        if (Database::num_rows($result) > 0) {
3181
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3182
                $return[] = $row;
3183
            }
3184
        }
3185
        return $return;
3186
    }
3187
3188
    /**
3189
     * Get user's tags
3190
     * @param int field_id
3191
     * @param int user_id
3192
     * @return array
3193
     */
3194
    public static function get_user_tags($user_id, $field_id)
3195
    {
3196
        // database table definition
3197
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3198
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3199
        $field_id = intval($field_id);
3200
        $user_id = intval($user_id);
3201
3202
        // all the information of the field
3203
        $sql = "SELECT ut.id, tag, count
3204
                FROM $table_user_tag ut
3205
                INNER JOIN $table_user_tag_values uv
3206
                ON (uv.tag_id=ut.ID)
3207
                WHERE field_id = $field_id AND user_id = $user_id
3208
                ORDER BY tag";
3209
        $result = Database::query($sql);
3210
        $return = array();
3211 View Code Duplication
        if (Database::num_rows($result) > 0) {
3212
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3213
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3214
            }
3215
        }
3216
3217
        return $return;
3218
    }
3219
3220
    /**
3221
     * Get user's tags
3222
     * @param int user_id
3223
     * @param int field_id
3224
     * @param bool show links or not
3225
     * @return array
3226
     */
3227
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3228
    {
3229
        // database table definition
3230
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3231
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3232
        $field_id = intval($field_id);
3233
        $user_id = intval($user_id);
3234
3235
        // all the information of the field
3236
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3237
                INNER JOIN $table_user_tag_values uv
3238
                ON (uv.tag_id = ut.id)
3239
                WHERE field_id = $field_id AND user_id = $user_id
3240
                ORDER BY tag";
3241
3242
        $result = Database::query($sql);
3243
        $return = array();
3244 View Code Duplication
        if (Database::num_rows($result) > 0) {
3245
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3246
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3247
            }
3248
        }
3249
        $user_tags = $return;
3250
        $tag_tmp = array();
3251
        foreach ($user_tags as $tag) {
3252
            if ($show_links) {
3253
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.$tag['tag'].'</a>';
3254
            } else {
3255
                $tag_tmp[] = $tag['tag'];
3256
            }
3257
        }
3258
        if (is_array($user_tags) && count($user_tags) > 0) {
3259
            $return = implode(', ', $tag_tmp);
3260
        } else {
3261
            return '';
3262
        }
3263
        return $return;
3264
    }
3265
3266
    /**
3267
     * Get the tag id
3268
     * @param int tag
3269
     * @param int field_id
3270
     * @return int returns 0 if fails otherwise the tag id
3271
     */
3272
    public static function get_tag_id($tag, $field_id)
3273
    {
3274
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3275
        $tag = Database::escape_string($tag);
3276
        $field_id = intval($field_id);
3277
        //with COLLATE latin1_bin to select query in a case sensitive mode
3278
        $sql = "SELECT id FROM $table_user_tag
3279
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3280
        $result = Database::query($sql);
3281
        if (Database::num_rows($result) > 0) {
3282
            $row = Database::fetch_array($result, 'ASSOC');
3283
            return $row['id'];
3284
        } else {
3285
            return 0;
3286
        }
3287
    }
3288
3289
    /**
3290
     * Get the tag id
3291
     * @param int tag
3292
     * @param int field_id
3293
     * @return int 0 if fails otherwise the tag id
3294
     */
3295 View Code Duplication
    public static function get_tag_id_from_id($tag_id, $field_id)
3296
    {
3297
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3298
        $tag_id = intval($tag_id);
3299
        $field_id = intval($field_id);
3300
        $sql = "SELECT id FROM $table_user_tag
3301
                WHERE id = '$tag_id' AND field_id = $field_id";
3302
        $result = Database::query($sql);
3303
        if (Database::num_rows($result) > 0) {
3304
            $row = Database::fetch_array($result, 'ASSOC');
3305
            return $row['id'];
3306
        } else {
3307
            return false;
3308
        }
3309
    }
3310
3311
    /**
3312
     * Adds a user-tag value
3313
     * @param mixed tag
3314
     * @param int The user id
3315
     * @param int field id of the tag
3316
     * @return bool
3317
     */
3318
    public static function add_tag($tag, $user_id, $field_id)
3319
    {
3320
        // database table definition
3321
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3322
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3323
        $tag = trim(Database::escape_string($tag));
3324
        $user_id = intval($user_id);
3325
        $field_id = intval($field_id);
3326
3327
        $tag_id = UserManager::get_tag_id($tag, $field_id);
3328
3329
        /* IMPORTANT
3330
         *  @todo we don't create tags with numbers
3331
         *
3332
         */
3333
        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...
3334
            //the form is sending an id this means that the user select it from the list so it MUST exists
3335
            /* $new_tag_id = UserManager::get_tag_id_from_id($tag,$field_id);
3336
              if ($new_tag_id !== false) {
3337
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3338
              $result = Database::query($sql);
3339
              $last_insert_id = $new_tag_id;
3340
              } else {
3341
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3342
              $result = Database::query($sql);
3343
              $last_insert_id = Database::insert_id();
3344
              } */
3345
        } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches 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 else branches can be removed.

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

could be turned into

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

This is much more concise to read.

Loading history...
3346
3347
        }
3348
3349
        //this is a new tag
3350
        if ($tag_id == 0) {
3351
            //the tag doesn't exist
3352
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3353
             Database::query($sql);
3354
            $last_insert_id = Database::insert_id();
3355
        } else {
3356
            //the tag exists we update it
3357
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3358
             Database::query($sql);
3359
            $last_insert_id = $tag_id;
3360
        }
3361
3362
        if (!empty($last_insert_id) && ($last_insert_id != 0)) {
3363
            //we insert the relationship user-tag
3364
            $sql = "SELECT tag_id FROM $table_user_tag_values
3365
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3366
            $result = Database::query($sql);
3367
            //if the relationship does not exist we create it
3368
            if (Database::num_rows($result) == 0) {
3369
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3370
                Database::query($sql);
3371
            }
3372
        }
3373
    }
3374
3375
    /**
3376
     * Deletes an user tag
3377
     * @param int user id
3378
     * @param int field id
3379
     *
3380
     */
3381
    public static function delete_user_tags($user_id, $field_id)
3382
    {
3383
        // database table definition
3384
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3385
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3386
        $tags = UserManager::get_user_tags($user_id, $field_id);
3387
        if (is_array($tags) && count($tags) > 0) {
3388
            foreach ($tags as $key => $tag) {
3389
                if ($tag['count'] > '0') {
3390
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3391
                    Database::query($sql);
3392
                }
3393
                $sql = "DELETE FROM $table_user_tag_values
3394
                        WHERE user_id = $user_id AND tag_id = $key";
3395
                Database::query($sql);
3396
            }
3397
        }
3398
    }
3399
3400
    /**
3401
     * Process the tag list comes from the UserManager::update_extra_field_value() function
3402
     * @param array the tag list that will be added
3403
     * @param int user id
3404
     * @param int field id
3405
     * @return bool
3406
     */
3407
    public static function process_tags($tags, $user_id, $field_id)
3408
    {
3409
        // We loop the tags and add it to the DB
3410
        if (is_array($tags)) {
3411
            foreach ($tags as $tag) {
3412
                UserManager::add_tag($tag, $user_id, $field_id);
3413
            }
3414
        } else {
3415
            UserManager::add_tag($tags, $user_id, $field_id);
3416
        }
3417
3418
        return true;
3419
    }
3420
3421
    /**
3422
     * Returns a list of all administrators
3423
     * @author jmontoya
3424
     * @return array
3425
     */
3426
    public static function get_all_administrators()
3427
    {
3428
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3429
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3430
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3431
        $access_url_id = api_get_current_access_url_id();
3432
        if (api_get_multiple_access_url()) {
3433
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3434
                    FROM $tbl_url_rel_user as url
3435
                    INNER JOIN $table_admin as admin
3436
                    ON (admin.user_id=url.user_id)
3437
                    INNER JOIN $table_user u
3438
                    ON (u.id=admin.user_id)
3439
                    WHERE access_url_id ='".$access_url_id."'";
3440
        } else {
3441
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3442
                    FROM $table_admin as admin
3443
                    INNER JOIN $table_user u
3444
                    ON (u.id=admin.user_id)";
3445
        }
3446
        $result = Database::query($sql);
3447
        $return = array();
3448
        if (Database::num_rows($result) > 0) {
3449
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3450
                $return[$row['user_id']] = $row;
3451
            }
3452
        }
3453
3454
        return $return;
3455
    }
3456
3457
    /**
3458
     * Search an user (tags, first name, last name and email )
3459
     * @param string $tag
3460
     * @param int $field_id field id of the tag
3461
     * @param int $from where to start in the query
3462
     * @param int $number_of_items
3463
     * @param bool $getCount get count or not
3464
     * @return array
3465
     */
3466
    public static function get_all_user_tags(
3467
        $tag,
3468
        $field_id = 0,
3469
        $from = 0,
3470
        $number_of_items = 10,
3471
        $getCount = false
3472
    ) {
3473
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3474
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3475
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3476
        $access_url_rel_user_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3477
3478
        $field_id = intval($field_id);
3479
        $from = intval($from);
3480
        $number_of_items = intval($number_of_items);
3481
3482
        $where_field = "";
3483
        $where_extra_fields = UserManager::get_search_form_where_extra_fields();
3484
        if ($field_id != 0) {
3485
            $where_field = " field_id = $field_id AND ";
3486
        }
3487
3488
        // all the information of the field
3489
3490
        if ($getCount) {
3491
            $select = "SELECT count(DISTINCT u.id) count";
3492
        } else {
3493
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3494
        }
3495
3496
        $sql = " $select
3497
                FROM $user_table u
3498
                INNER JOIN $access_url_rel_user_table url_rel_user
3499
                ON (u.id = url_rel_user.user_id)
3500
                LEFT JOIN $table_user_tag_values uv
3501
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3502
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3503
                WHERE
3504
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3505
                    (
3506
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3507
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3508
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3509
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3510
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3511
                     )
3512
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3513
                     AND
3514
                     url_rel_user.access_url_id=".api_get_current_access_url_id();
3515
3516
        $keyword_active = true;
3517
        // only active users
3518
        if ($keyword_active) {
3519
            $sql .= " AND u.active='1'";
3520
        }
3521
        // avoid anonymous
3522
        $sql .= " AND u.status <> 6 ";
3523
        $sql .= " ORDER BY username";
3524
        $sql .= " LIMIT $from , $number_of_items";
3525
3526
        $result = Database::query($sql);
3527
        $return = array();
3528
3529
        if (Database::num_rows($result) > 0) {
3530
            if ($getCount) {
3531
                $row = Database::fetch_array($result, 'ASSOC');
3532
                return $row['count'];
3533
            }
3534
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3535
                if (isset($return[$row['id']]) &&
3536
                    !empty($return[$row['id']]['tag'])
3537
                ) {
3538
                    $url = Display::url(
3539
                        $row['tag'],
3540
                        api_get_path(WEB_PATH).'main/social/search.php?q='.$row['tag'],
3541
                        array('class' => 'tag')
3542
                    );
3543
                    $row['tag'] = $url;
3544
                }
3545
                $return[$row['id']] = $row;
3546
            }
3547
        }
3548
3549
        return $return;
3550
    }
3551
3552
    /**
3553
      * Get extra filtrable user fields (only type select)
3554
      * @return array
3555
      */
3556
    public static function get_extra_filtrable_fields()
3557
    {
3558
        $extraFieldList = UserManager::get_extra_fields();
3559
3560
        $extraFiltrableFields = array();
3561 View Code Duplication
        if (is_array($extraFieldList)) {
3562
            foreach ($extraFieldList as $extraField) {
3563
                // If is enabled to filter and is a "<select>" field type
3564
                if ($extraField[8] == 1 && $extraField[2] == 4) {
3565
                    $extraFiltrableFields[] = array(
3566
                        'name' => $extraField[3],
3567
                        'variable' => $extraField[1],
3568
                        'data' => $extraField[9]
3569
                    );
3570
                }
3571
            }
3572
        }
3573
3574
        if (is_array($extraFiltrableFields) && count($extraFiltrableFields) > 0) {
3575
            return $extraFiltrableFields;
3576
        }
3577
    }
3578
3579
    /**
3580
      * Get extra where clauses for finding users based on extra filtrable user fields (type select)
3581
      * @return string With AND clauses based on user's ID which have the values to search in extra user fields
3582
      */
3583
    public static function get_search_form_where_extra_fields()
3584
    {
3585
        $useExtraFields = false;
3586
        $extraFields = UserManager::get_extra_filtrable_fields();
3587
        $extraFieldResult = array();
3588 View Code Duplication
        if (is_array($extraFields) && count($extraFields)>0 ) {
3589
            foreach ($extraFields as $extraField) {
3590
                $varName = 'field_'.$extraField['variable'];
3591
                if (UserManager::is_extra_field_available($extraField['variable'])) {
3592
                    if (isset($_GET[$varName]) && $_GET[$varName]!='0') {
3593
                        $useExtraFields = true;
3594
                        $extraFieldResult[]= UserManager::get_extra_user_data_by_value(
3595
                            $extraField['variable'],
3596
                            $_GET[$varName]
3597
                        );
3598
                    }
3599
                }
3600
            }
3601
        }
3602
3603
        if ($useExtraFields) {
3604
            $finalResult = array();
3605
            if (count($extraFieldResult)>1) {
3606
                for ($i=0; $i < count($extraFieldResult) -1; $i++) {
3607
                    if (is_array($extraFieldResult[$i+1])) {
3608
                        $finalResult  = array_intersect($extraFieldResult[$i], $extraFieldResult[$i+1]);
3609
                    }
3610
                }
3611
            } else {
3612
                $finalResult = $extraFieldResult[0];
3613
            }
3614
3615
            if (is_array($finalResult) && count($finalResult)>0) {
3616
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
3617
            } else {
3618
                //no results
3619
                $whereFilter = " AND u.id  = -1 ";
3620
            }
3621
3622
            return $whereFilter;
3623
        }
3624
    }
3625
3626
    /**
3627
     * Show the search form
3628
     * @param string $query the value of the search box
3629
     * @return string HTML form
3630
     */
3631
    public static function get_search_form($query)
3632
    {
3633
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
3634
        $form = new FormValidator(
3635
            'search_user',
3636
            'get',
3637
            api_get_path(WEB_PATH).'main/social/search.php',
3638
            '',
3639
            array(),
3640
            FormValidator::LAYOUT_HORIZONTAL
3641
        );
3642
3643
        $form->addText('q', get_lang('UsersGroups'), false);
3644
        $options = array(
3645
            0 => get_lang('Select'),
3646
            1 => get_lang('User'),
3647
            2 => get_lang('Group'),
3648
        );
3649
        $form->addSelect(
3650
            'search_type',
3651
            get_lang('Type'),
3652
            $options,
3653
            array('onchange' => 'javascript: extra_field_toogle();')
3654
        );
3655
3656
        // Extra fields
3657
3658
        $extraFields = UserManager::get_extra_filtrable_fields();
3659
        $defaults = [];
3660
        if (is_array($extraFields) && count($extraFields) > 0) {
3661
            foreach ($extraFields as $extraField) {
3662
                $varName = 'field_'.$extraField['variable'];
3663
3664
                $options = [
3665
                    0 => get_lang('Select')
3666
                ];
3667
                foreach ($extraField['data'] as $option) {
3668
                    $checked = '';
3669
                    if (isset($_GET[$varName])) {
3670
                        if ($_GET[$varName] == $option[1]) {
3671
                            $defaults[$option[1]] = true;
3672
                        }
3673
                    }
3674
3675
                    $options[$option[1]] = $option[1];
3676
                }
3677
                $form->addSelect($varName, $extraField['name'], $options);
3678
            }
3679
        }
3680
3681
        $defaults['search_type'] = intval($searchType);
3682
        $defaults['q'] = api_htmlentities(Security::remove_XSS($query));
3683
        $form->setDefaults($defaults);
3684
3685
        $form->addButtonSearch(get_lang('Search'));
3686
3687
        $js = '<script>
3688
        extra_field_toogle();
3689
        function extra_field_toogle() {
3690
            if (jQuery("select[name=search_type]").val() != "1") { jQuery(".extra_field").hide(); } else { jQuery(".extra_field").show(); }
3691
        }
3692
        </script>';
3693
3694
        return $js.$form->returnForm();
3695
    }
3696
3697
    /**
3698
     * Shows the user menu
3699
     */
3700
    public static function show_menu()
3701
    {
3702
        echo '<div class="actions">';
3703
        echo '<a href="/main/auth/profile.php">'.Display::return_icon('profile.png').' '.get_lang('PersonalData').'</a>';
3704
        echo '<a href="/main/messages/inbox.php">'.Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
3705
        echo '<a href="/main/messages/outbox.php">'.Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
3706
        echo '<span style="float:right; padding-top:7px;">'.
3707
        '<a href="/main/auth/profile.php?show=1">'.Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
3708
        '</span>';
3709
        echo '</div>';
3710
    }
3711
3712
    /**
3713
     * Allow to register contact to social network
3714
     * @param int $friend_id user friend id
3715
     * @param int $my_user_id user id
3716
     * @param int $relation_type relation between users see constants definition
3717
     */
3718
    public static function relate_users($friend_id, $my_user_id, $relation_type)
3719
    {
3720
        $tbl_my_friend = Database :: get_main_table(TABLE_MAIN_USER_REL_USER);
3721
3722
        $friend_id = intval($friend_id);
3723
        $my_user_id = intval($my_user_id);
3724
        $relation_type = intval($relation_type);
3725
3726
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
3727
                WHERE
3728
                    friend_user_id='.$friend_id.' AND
3729
                    user_id='.$my_user_id.' AND
3730
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
3731
        $result = Database::query($sql);
3732
        $row = Database :: fetch_array($result, 'ASSOC');
3733
        $current_date = date('Y-m-d H:i:s');
3734
3735
        if ($row['count'] == 0) {
3736
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
3737
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
3738
            Database::query($sql);
3739
            return true;
3740
        } else {
3741
            $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
3742
                    WHERE
3743
                        friend_user_id='.$friend_id.' AND
3744
                        user_id='.$my_user_id.' AND
3745
                        relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
3746
            $result = Database::query($sql);
3747
            $row = Database :: fetch_array($result, 'ASSOC');
3748
            if ($row['count'] == 1) {
3749
                //only for the case of a RRHH
3750
                if ($row['relation_type'] != $relation_type && $relation_type == USER_RELATION_TYPE_RRHH) {
3751
                    $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
3752
                            VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
3753
                } else {
3754
                    $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
3755
                            WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
3756
                }
3757
                Database::query($sql);
3758
3759
                return true;
3760
            } else {
3761
3762
                return false;
3763
            }
3764
        }
3765
    }
3766
3767
    /**
3768
     * Deletes a contact
3769
     * @param int user friend id
3770
     * @param bool true will delete ALL friends relationship from $friend_id
3771
     * @author isaac flores paz <[email protected]>
3772
     * @author Julio Montoya <[email protected]> Cleaning code
3773
     */
3774
    public static function remove_user_rel_user($friend_id, $real_removed = false, $with_status_condition = '')
3775
    {
3776
        $tbl_my_friend = Database :: get_main_table(TABLE_MAIN_USER_REL_USER);
3777
        $tbl_my_message = Database :: get_main_table(TABLE_MESSAGE);
3778
        $friend_id = intval($friend_id);
3779
3780
        if ($real_removed) {
3781
            $extra_condition = '';
3782
            if ($with_status_condition != '') {
3783
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
3784
            }
3785
            $sql = 'DELETE FROM '.$tbl_my_friend.'
3786
                    WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND friend_user_id='.$friend_id.' '.$extra_condition;
3787
            Database::query($sql);
3788
            $sql= 'DELETE FROM '.$tbl_my_friend.'
3789
                   WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND user_id='.$friend_id.' '.$extra_condition;
3790
            Database::query($sql);
3791
        } else {
3792
            $user_id = api_get_user_id();
3793
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
3794
                    WHERE
3795
                        user_id='.$user_id.' AND
3796
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
3797
                        friend_user_id='.$friend_id;
3798
            $result = Database::query($sql);
3799
            $row = Database :: fetch_array($result, 'ASSOC');
3800
            if ($row['count'] == 1) {
3801
                //Delete user rel user
3802
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
3803
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
3804
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
3805
                          WHERE user_receiver_id='.$user_id.' AND user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
3806
                //Delete user
3807
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
3808
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
3809
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
3810
                           WHERE user_receiver_id='.$friend_id.' AND user_sender_id='.$user_id.' AND update_date="0000-00-00 00:00:00" ';
3811
                Database::query($sql_i);
3812
                Database::query($sql_j);
3813
                Database::query($sql_ij);
3814
                Database::query($sql_ji);
3815
            }
3816
        }
3817
    }
3818
3819
    /**
3820
     * @param int $userId
3821
     * @return array
3822
     */
3823
    public static function getDrhListFromUser($userId)
3824
    {
3825
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
3826
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
3827
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3828
        $userId = intval($userId);
3829
3830
        $orderBy = null;
3831
        if (api_is_western_name_order()) {
3832
            $orderBy .= " ORDER BY firstname, lastname ";
3833
        } else {
3834
            $orderBy .= " ORDER BY lastname, firstname ";
3835
        }
3836
3837
        $sql = "SELECT u.id, username, u.firstname, u.lastname
3838
                FROM $tblUser u
3839
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
3840
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
3841
                WHERE
3842
                    access_url_id = ".api_get_current_access_url_id()." AND
3843
                    uru.user_id = '$userId' AND
3844
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
3845
                $orderBy
3846
                ";
3847
        $result = Database::query($sql);
3848
3849
        return Database::store_result($result);
3850
    }
3851
3852
    /**
3853
     * get users followed by human resource manager
3854
     * @param int $userId
3855
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
3856
     * @param bool $getOnlyUserId
3857
     * @param bool $getSql
3858
     * @param bool $getCount
3859
     * @param int $from
3860
     * @param int $numberItems
3861
     * @param int $column
3862
     * @param string $direction
3863
     * @param int $active
3864
     * @param string $lastConnectionDate
3865
     * @return array     users
3866
     */
3867 View Code Duplication
    public static function get_users_followed_by_drh(
3868
        $userId,
3869
        $userStatus = 0,
3870
        $getOnlyUserId = false,
3871
        $getSql = false,
3872
        $getCount = false,
3873
        $from = null,
3874
        $numberItems = null,
3875
        $column = null,
3876
        $direction = null,
3877
        $active = null,
3878
        $lastConnectionDate = null
3879
    ) {
3880
        return self::getUsersFollowedByUser(
3881
            $userId,
3882
            $userStatus,
3883
            $getOnlyUserId,
3884
            $getSql,
3885
            $getCount,
3886
            $from,
3887
            $numberItems,
3888
            $column,
3889
            $direction,
3890
            $active,
3891
            $lastConnectionDate,
3892
            DRH
3893
        );
3894
    }
3895
3896
    /**
3897
    * Get users followed by human resource manager
3898
    * @param int $userId
3899
    * @param int  $userStatus Filter users by status (STUDENT, COURSEMANAGER, etc)
3900
    * @param bool $getOnlyUserId
3901
    * @param bool $getSql
3902
    * @param bool $getCount
3903
    * @param int $from
3904
    * @param int $numberItems
3905
    * @param int $column
3906
    * @param string $direction
3907
    * @param int $active
3908
    * @param string $lastConnectionDate
3909
    * @param int $status the function is called by who? COURSEMANAGER, DRH?
3910
    * @param string $keyword
3911
     *
3912
    * @return array user list
3913
    */
3914
    public static function getUsersFollowedByUser(
3915
        $userId,
3916
        $userStatus = null,
3917
        $getOnlyUserId = false,
3918
        $getSql = false,
3919
        $getCount = false,
3920
        $from = null,
3921
        $numberItems = null,
3922
        $column = null,
3923
        $direction = null,
3924
        $active = null,
3925
        $lastConnectionDate = null,
3926
        $status = null,
3927
        $keyword = null
3928
    ) {
3929
        // Database Table Definitions
3930
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
3931
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
3932
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3933
3934
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3935
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3936
3937
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3938
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3939
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3940
3941
        $userId = intval($userId);
3942
3943
        $limitCondition = null;
3944
3945 View Code Duplication
        if (isset($from) && isset($numberItems)) {
3946
            $from = intval($from);
3947
            $numberItems = intval($numberItems);
3948
            $limitCondition = "LIMIT $from, $numberItems";
3949
        }
3950
3951
        $column = Database::escape_string($column);
3952
        $direction = in_array(strtolower($direction), array('asc', 'desc')) ? $direction : null;
3953
3954
        $userConditions = '';
3955
        if (!empty($userStatus)) {
3956
            $userConditions .= ' AND u.status = '.intval($userStatus);
3957
        }
3958
3959
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
3960
        if ($getOnlyUserId) {
3961
            $select = " SELECT DISTINCT u.id user_id";
3962
        }
3963
3964
        $masterSelect = "SELECT DISTINCT * FROM ";
3965
3966
        if ($getCount) {
3967
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
3968
            $select = " SELECT DISTINCT(u.id) user_id";
3969
        }
3970
3971
        if (!is_null($active)) {
3972
            $active = intval($active);
3973
            $userConditions .= " AND u.active = $active ";
3974
        }
3975
3976 View Code Duplication
        if (!empty($keyword)) {
3977
            $keyword = Database::escape_string($keyword);
3978
            $userConditions .= " AND (
3979
                u.username LIKE '%$keyword%' OR
3980
                u.firstname LIKE '%$keyword%' OR
3981
                u.lastname LIKE '%$keyword%' OR
3982
                u.official_code LIKE '%$keyword%' OR
3983
                u.email LIKE '%$keyword%'
3984
            )";
3985
        }
3986
3987
        if (!empty($lastConnectionDate)) {
3988
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
3989
            $userConditions .=  " AND u.last_login <= '$lastConnectionDate' ";
3990
        }
3991
3992
        $courseConditions = null;
3993
        $sessionConditionsCoach = null;
3994
        $sessionConditionsTeacher = null;
3995
        $drhConditions = null;
3996
        $teacherSelect = null;
3997
3998
        switch ($status) {
3999
            case DRH:
4000
                $drhConditions .= " AND
4001
                    friend_user_id = '$userId' AND
4002
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4003
                ";
4004
                break;
4005
            case COURSEMANAGER:
4006
                $drhConditions .= " AND
4007
                    friend_user_id = '$userId' AND
4008
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4009
                ";
4010
4011
                $sessionConditionsCoach .= " AND
4012
                    (s.id_coach = '$userId')
4013
                ";
4014
4015
                $sessionConditionsTeacher .= " AND
4016
                    (scu.status = 2 AND scu.user_id = '$userId')
4017
                ";
4018
4019
                $teacherSelect =
4020
                "UNION ALL (
4021
                        $select
4022
                        FROM $tbl_user u
4023
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4024
                        WHERE
4025
                            sru.session_id IN (
4026
                                SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4027
                                $tbl_session_rel_access_url
4028
                                WHERE access_url_id = ".api_get_current_access_url_id()."
4029
                                $sessionConditionsCoach
4030
                                UNION (
4031
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4032
                                    INNER JOIN $tbl_session_rel_access_url url
4033
                                    ON (url.session_id = s.id)
4034
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4035
                                    ON (scu.session_id = s.id)
4036
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4037
                                    $sessionConditionsTeacher
4038
                                )
4039
                            )
4040
                            $userConditions
4041
                    )
4042
                    UNION ALL(
4043
                        $select
4044
                        FROM $tbl_user u
4045
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4046
                        WHERE cu.c_id IN (
4047
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4048
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4049
                        )
4050
                        $userConditions
4051
                    )"
4052
                ;
4053
                break;
4054
            case STUDENT_BOSS :
4055
                $drhConditions = " AND friend_user_id = $userId AND "
4056
                . "relation_type = " . USER_RELATION_TYPE_BOSS;
4057
                break;
4058
        }
4059
4060
        $join = null;
4061
        $sql = " $masterSelect
4062
                (
4063
                    (
4064
                        $select
4065
                        FROM $tbl_user u
4066
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4067
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4068
                        $join
4069
                        WHERE
4070
                            access_url_id = ".api_get_current_access_url_id()."
4071
                            $drhConditions
4072
                            $userConditions
4073
                    )
4074
                    $teacherSelect
4075
4076
                ) as t1";
4077
4078
        if ($getSql) {
4079
            return $sql;
4080
        }
4081
        if ($getCount) {
4082
            $result = Database::query($sql);
4083
            $row = Database::fetch_array($result);
4084
            return $row['count'];
4085
        }
4086
4087
        $orderBy = null;
4088
        if (api_is_western_name_order()) {
4089
            $orderBy .= " ORDER BY firstname, lastname ";
4090
        } else {
4091
            $orderBy .= " ORDER BY lastname, firstname ";
4092
        }
4093
4094 View Code Duplication
        if (!empty($column) && !empty($direction)) {
4095
            // Fixing order due the UNIONs
4096
            $column = str_replace('u.', '', $column);
4097
            $orderBy = " ORDER BY $column $direction ";
4098
        }
4099
4100
        $sql .= $orderBy;
4101
        $sql .= $limitCondition;
4102
        $result = Database::query($sql);
4103
        $users = array();
4104
        if (Database::num_rows($result) > 0) {
4105
4106
            while ($row = Database::fetch_array($result)) {
4107
                $users[$row['user_id']] = $row;
4108
            }
4109
        }
4110
4111
        return $users;
4112
    }
4113
4114
    /**
4115
     * Subscribes users to human resource manager (Dashboard feature)
4116
     *    @param    int         hr dept id
4117
     * @param    array        Users id
4118
     * @param    int            affected rows
4119
     * */
4120
    public static function suscribe_users_to_hr_manager($hr_dept_id, $users_id)
4121
    {
4122
        return self::subscribeUsersToUser($hr_dept_id, $users_id, USER_RELATION_TYPE_RRHH);
4123
    }
4124
4125
    /**
4126
     * Add subscribed users to a user by relation type
4127
     * @param int $userId The user id
4128
     * @param array $subscribedUsersId The id of suscribed users
4129
     * @param action $relationType The relation type
4130
     */
4131
    public static function subscribeUsersToUser($userId, $subscribedUsersId, $relationType, $deleteUsersBeforeInsert = false)
4132
    {
4133
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4134
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4135
4136
        $userId = intval($userId);
4137
        $relationType = intval($relationType);
4138
        $affectedRows = 0;
4139
4140
        if (api_get_multiple_access_url()) {
4141
            // Deleting assigned users to hrm_id
4142
            $sql = "SELECT s.user_id FROM $userRelUserTable s 
4143
                    INNER JOIN $userRelAccessUrlTable a ON (a.user_id = s.user_id) 
4144
                    WHERE 
4145
                        friend_user_id = $userId AND 
4146
                        relation_type = $relationType AND 
4147
                        access_url_id = " . api_get_current_access_url_id();
4148
        } else {
4149
            $sql = "SELECT user_id FROM $userRelUserTable 
4150
                    WHERE friend_user_id = $userId 
4151
                    AND relation_type = $relationType";
4152
        }
4153
        $result = Database::query($sql);
4154
4155 View Code Duplication
        if (Database::num_rows($result) > 0) {
4156
            while ($row = Database::fetch_array($result)) {
4157
                $sql = "DELETE FROM $userRelUserTable 
4158
                        WHERE 
4159
                          user_id = {$row['user_id']} AND 
4160
                          friend_user_id = $userId AND 
4161
                          relation_type = $relationType";
4162
                Database::query($sql);
4163
            }
4164
        }
4165
4166
        if ($deleteUsersBeforeInsert) {
4167
            $sql = "DELETE FROM $userRelUserTable 
4168
                    WHERE 
4169
                        user_id = $userId AND
4170
                        relation_type = $relationType";
4171
            Database::query($sql);
4172
        }
4173
4174
        // Inserting new user list
4175
        if (is_array($subscribedUsersId)) {
4176
            foreach ($subscribedUsersId as $subscribedUserId) {
4177
                $subscribedUserId = intval($subscribedUserId);
4178
4179
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4180
                        VALUES ($subscribedUserId, $userId, $relationType)";
4181
4182
                $result = Database::query($sql);
4183
                $affectedRows = Database::affected_rows($result);
4184
            }
4185
        }
4186
4187
        return $affectedRows;
4188
    }
4189
4190
    /**
4191
     * This function check if an user is followed by human resources manager
4192
     * @param     int     User id
4193
     * @param    int        Human resources manager
4194
     * @return    bool
4195
     */
4196
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4197
    {
4198
        // Database table and variables Definitions
4199
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4200
        $user_id = intval($user_id);
4201
        $hr_dept_id = intval($hr_dept_id);
4202
        $result = false;
4203
4204
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4205
                WHERE
4206
                    user_id = $user_id AND
4207
                    friend_user_id = $hr_dept_id AND
4208
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4209
        $rs = Database::query($sql);
4210
        if (Database::num_rows($rs) > 0) {
4211
            $result = true;
4212
        }
4213
        return $result;
4214
    }
4215
4216
    /**
4217
     * get user id of teacher or session administrator
4218
     * @param array $courseInfo
4219
     *
4220
     * @return int The user id
4221
     */
4222
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4223
    {
4224
        $session = api_get_session_id();
4225
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4226
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4227
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4228
        $courseId = $courseInfo['real_id'];
4229
        $courseCode = $courseInfo['code'];
4230
4231
        if ($session == 0 || is_null($session)) {
4232
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4233
                    INNER JOIN '.$table_course_user.' ru
4234
                    ON ru.user_id = u.id
4235
                    WHERE
4236
                        ru.status = 1 AND
4237
                        ru.c_id = "'.$courseId.'" ';
4238
            $rs = Database::query($sql);
4239
            $num_rows = Database::num_rows($rs);
4240
            if ($num_rows == 1) {
4241
                $row = Database::fetch_array($rs);
4242
                return $row['uid'];
4243
            } else {
4244
                $my_num_rows = $num_rows;
4245
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4246
                return $my_user_id;
4247
            }
4248
        } elseif ($session > 0) {
4249
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4250
                    INNER JOIN '.$table_session_course_user.' sru
4251
                    ON sru.user_id=u.id
4252
                    WHERE
4253
                        sru.c_id="'.$courseId.'" AND
4254
                        sru.status=2';
4255
            $rs = Database::query($sql);
4256
            $row = Database::fetch_array($rs);
4257
4258
            return $row['uid'];
4259
        }
4260
    }
4261
4262
    /**
4263
     * Determines if a user is a gradebook certified
4264
     * @param int The category id of gradebook
4265
     * @param int The user id
4266
     * @return boolean
4267
     */
4268
    public static function is_user_certified($cat_id, $user_id)
4269
    {
4270
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4271
        $sql = 'SELECT path_certificate FROM '.$table_certificate.'
4272
                WHERE
4273
                    cat_id="'.intval($cat_id).'" AND
4274
                    user_id="'.intval($user_id).'"';
4275
        $rs = Database::query($sql);
4276
        $row = Database::fetch_array($rs);
4277
        if ($row['path_certificate'] == '' || is_null($row['path_certificate'])) {
4278
            return false;
4279
        } else {
4280
            return true;
4281
        }
4282
    }
4283
4284
    /**
4285
     * Gets the info about a gradebook certificate for a user by course
4286
     * @param string The course code
4287
     * @param int The user id
4288
     * @return array  if there is not information return false
4289
     */
4290
    public static function get_info_gradebook_certificate($course_code, $user_id)
4291
    {
4292
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4293
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4294
        $session_id = api_get_session_id();
4295
4296
        if (empty($session_id)) {
4297
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4298
        } else {
4299
            $session_condition = " AND session_id = $session_id";
4300
        }
4301
4302
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.' WHERE cat_id = (SELECT id FROM '.$tbl_grade_category.'
4303
                WHERE
4304
                    course_code = "'.Database::escape_string($course_code).'" '.$session_condition.' LIMIT 1 ) AND
4305
                    user_id='.intval($user_id);
4306
4307
        $rs = Database::query($sql);
4308
        if (Database::num_rows($rs) > 0) {
4309
            $row = Database::fetch_array($rs, 'ASSOC');
4310
            $score = $row['score_certificate'];
4311
            $category_id = $row['cat_id'];
4312
            $cat = Category::load($category_id);
4313
            $displayscore = ScoreDisplay::instance();
4314
            if (isset($cat) && $displayscore->is_custom()) {
4315
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()), SCORE_DIV_PERCENT_WITH_CUSTOM);
4316
            } else {
4317
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()));
4318
            }
4319
            $row['grade'] = $grade;
4320
            return $row;
4321
        }
4322
        return false;
4323
    }
4324
4325
    /**
4326
     * Gets the user path of user certificated
4327
     * @param int The user id
4328
     * @return array  containing path_certificate and cat_id
4329
     */
4330
    public static function get_user_path_certificate($user_id)
4331
    {
4332
        $my_certificate = array();
4333
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4334
        $table_gradebook_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4335
4336
        $session_id = api_get_session_id();
4337
        $user_id = intval($user_id);
4338 View Code Duplication
        if ($session_id == 0 || is_null($session_id)) {
4339
            $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
4340
        } elseif ($session_id > 0) {
4341
            $sql_session = 'AND session_id='.intval($session_id);
4342
        } else {
4343
            $sql_session = '';
4344
        }
4345
        $sql = "SELECT tc.path_certificate,tc.cat_id,tgc.course_code,tgc.name
4346
                FROM $table_certificate tc, $table_gradebook_category tgc
4347
                WHERE tgc.id = tc.cat_id AND tc.user_id = $user_id
4348
                ORDER BY tc.date_certificate DESC limit 5";
4349
4350
        $rs = Database::query($sql);
4351
        while ($row = Database::fetch_array($rs)) {
4352
            $my_certificate[] = $row;
4353
        }
4354
        return $my_certificate;
4355
    }
4356
4357
    /**
4358
     * This function check if the user is a coach inside session course
4359
     * @param  int     User id
4360
     * @param  int  $courseId
4361
     * @param  int     Session id
4362
     * @return bool    True if the user is a coach
4363
     *
4364
     */
4365
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4366
    {
4367
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4368
        // Protect data
4369
        $user_id = intval($user_id);
4370
        $courseId = intval($courseId);
4371
        $session_id = intval($session_id);
4372
        $result = false;
4373
4374
        $sql = "SELECT session_id FROM $tbl_session_course_rel_user
4375
                WHERE
4376
                  session_id = $session_id AND
4377
                  c_id = $courseId AND
4378
                  user_id = $user_id AND
4379
                  status = 2 ";
4380
        $res = Database::query($sql);
4381
4382
        if (Database::num_rows($res) > 0) {
4383
            $result = true;
4384
        }
4385
        return $result;
4386
    }
4387
4388
    /**
4389
     * This function returns an icon path that represents the favicon of the website of which the url given.
4390
     * Defaults to the current Chamilo favicon
4391
     * @param    string    URL of website where to look for favicon.ico
4392
     * @param    string    Optional second URL of website where to look for favicon.ico
4393
     * @return    string    Path of icon to load
4394
     */
4395
    public static function get_favicon_from_url($url1, $url2 = null)
4396
    {
4397
        $icon_link = '';
4398
        $url = $url1;
4399
        if (empty($url1)) {
4400
            $url = $url2;
4401
            if (empty($url)) {
4402
                $url = api_get_access_url(api_get_current_access_url_id());
4403
                $url = $url[0];
4404
            }
4405
        }
4406
        if (!empty($url)) {
4407
            $pieces = parse_url($url);
4408
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
4409
        }
4410
        return $icon_link;
4411
    }
4412
4413
    /**
4414
     *
4415
     * @param int   student id
4416
     * @param int   years
4417
     * @param bool  show warning_message
4418
     * @param bool  return_timestamp
4419
     */
4420
    public static function delete_inactive_student($student_id, $years = 2, $warning_message = false, $return_timestamp = false)
4421
    {
4422
        $tbl_track_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
4423
        $sql = 'SELECT login_date FROM '.$tbl_track_login.'
4424
                WHERE login_user_id = '.intval($student_id).'
4425
                ORDER BY login_date DESC LIMIT 0,1';
4426
        if (empty($years)) {
4427
            $years = 1;
4428
        }
4429
        $inactive_time = $years * 31536000;  //1 year
4430
        $rs = Database::query($sql);
4431
        if (Database::num_rows($rs) > 0) {
4432
            if ($last_login_date = Database::result($rs, 0, 0)) {
4433
                $last_login_date = api_get_local_time($last_login_date, null, date_default_timezone_get());
4434
                if ($return_timestamp) {
4435
                    return api_strtotime($last_login_date);
4436
                } else {
4437
                    if (!$warning_message) {
4438
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
4439
                    } else {
4440
                        $timestamp = api_strtotime($last_login_date);
4441
                        $currentTimestamp = time();
4442
4443
                        //If the last connection is > than 7 days, the text is red
4444
                        //345600 = 7 days in seconds 63072000= 2 ans
4445
                        // if ($currentTimestamp - $timestamp > 184590 )
4446
                        if ($currentTimestamp - $timestamp > $inactive_time && UserManager::delete_user($student_id)) {
4447
                            Display :: display_normal_message(get_lang('UserDeleted'));
4448
                            echo '<p>', 'id', $student_id, ':', $last_login_date, '</p>';
4449
                        }
4450
                    }
4451
                }
4452
            }
4453
        }
4454
        return false;
4455
    }
4456
4457
    /**
4458
     * @param FormValidator $form
4459
     * @param $extra_data
4460
     * @param $form_name
4461
     * @param bool $admin_permissions
4462
     * @param null $user_id
4463
     * @deprecated
4464
     * @return array
4465
     */
4466
    static function set_extra_fields_in_form(
4467
        $form,
4468
        $extra_data,
4469
        $admin_permissions = false,
4470
        $user_id = null
4471
    ) {
4472
        $user_id = intval($user_id);
4473
4474
        // EXTRA FIELDS
4475
        $extra = UserManager::get_extra_fields(0, 50, 5, 'ASC');
4476
        $jquery_ready_content = null;
4477
        foreach ($extra as $field_details) {
4478
4479
            if (!$admin_permissions) {
4480
                if ($field_details[6] == 0) {
4481
                    continue;
4482
                }
4483
            }
4484
4485
            switch ($field_details[2]) {
4486 View Code Duplication
                case ExtraField::FIELD_TYPE_TEXT:
4487
                    $form->addElement('text', 'extra_'.$field_details[1], $field_details[3], array('size' => 40));
4488
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4489
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4490
                    $form->applyFilter('extra_'.$field_details[1], 'html_filter');
4491
4492
                    if (!$admin_permissions) {
4493
                        if ($field_details[7] == 0) {
4494
                            $form->freeze('extra_'.$field_details[1]);
4495
                        }
4496
                    }
4497
                    break;
4498 View Code Duplication
                case ExtraField::FIELD_TYPE_TEXTAREA:
4499
                    $form->addHtmlEditor(
4500
                        'extra_'.$field_details[1],
4501
                        $field_details[3],
4502
                        false,
4503
                        false,
4504
                        array('ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130')
4505
                    );
4506
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4507
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4508
                    if (!$admin_permissions) {
4509
                        if ($field_details[7] == 0)
4510
                            $form->freeze('extra_'.$field_details[1]);
4511
                    }
4512
                    break;
4513
                case ExtraField::FIELD_TYPE_RADIO:
4514
                    $group = array();
4515 View Code Duplication
                    foreach ($field_details[9] as $option_id => $option_details) {
4516
                        $options[$option_details[1]] = $option_details[2];
4517
                        $group[] = $form->createElement(
4518
                            'radio',
4519
                            'extra_'.$field_details[1],
4520
                            $option_details[1],
4521
                            $option_details[2].'<br />',
4522
                            $option_details[1]
4523
                        );
4524
                    }
4525
                    $form->addGroup($group, 'extra_'.$field_details[1], $field_details[3], '');
4526
                    if (!$admin_permissions) {
4527
                        if ($field_details[7] == 0)
4528
                            $form->freeze('extra_'.$field_details[1]);
4529
                    }
4530
                    break;
4531
                case ExtraField::FIELD_TYPE_SELECT:
4532
                    $get_lang_variables = false;
4533 View Code Duplication
                    if (in_array(
4534
                        $field_details[1],
4535
                        array(
4536
                            'mail_notify_message',
4537
                            'mail_notify_invitation',
4538
                            'mail_notify_group_message',
4539
                        )
4540
                    )) {
4541
                        $get_lang_variables = true;
4542
                    }
4543
                    $options = array();
4544
4545
                    foreach ($field_details[9] as $option_id => $option_details) {
4546
                        if ($get_lang_variables) {
4547
                            $options[$option_details[1]] = get_lang($option_details[2]);
4548
                        } else {
4549
                            $options[$option_details[1]] = $option_details[2];
4550
                        }
4551
                    }
4552
4553
                    if ($get_lang_variables) {
4554
                        $field_details[3] = get_lang($field_details[3]);
4555
                    }
4556
4557
                    $form->addElement(
4558
                        'select',
4559
                        'extra_'.$field_details[1],
4560
                        $field_details[3],
4561
                        $options,
4562
                        array('id' => 'extra_' . $field_details[1])
4563
                    );
4564
4565
                    if (!$admin_permissions) {
4566
                        if ($field_details[7] == 0)
4567
                            $form->freeze('extra_'.$field_details[1]);
4568
                    }
4569
                    break;
4570 View Code Duplication
                case ExtraField::FIELD_TYPE_SELECT_MULTIPLE:
4571
                    $options = array();
4572
                    foreach ($field_details[9] as $option_id => $option_details) {
4573
                        $options[$option_details[1]] = $option_details[2];
4574
                    }
4575
                    $form->addElement(
4576
                        'select',
4577
                        'extra_'.$field_details[1],
4578
                        $field_details[3],
4579
                        $options,
4580
                        array('multiple' => 'multiple')
4581
                    );
4582
                    if (!$admin_permissions) {
4583
                        if ($field_details[7] == 0)
4584
                            $form->freeze('extra_'.$field_details[1]);
4585
                    }
4586
                    break;
4587 View Code Duplication
                case ExtraField::FIELD_TYPE_DATE:
4588
                    $form->addDatePicker('extra_'.$field_details[1], $field_details[3]);
4589
                    $defaults['extra_'.$field_details[1]] = date('Y-m-d 12:00:00');
4590
                    $form->setDefaults($defaults);
4591
                    if (!$admin_permissions) {
4592
                        if ($field_details[7] == 0)
4593
                            $form->freeze('extra_'.$field_details[1]);
4594
                    }
4595
                    $form->applyFilter('theme', 'trim');
4596
                    break;
4597 View Code Duplication
                case ExtraField::FIELD_TYPE_DATETIME:
4598
                    $form->addDateTimePicker('extra_'.$field_details[1], $field_details[3]);
4599
                    $defaults['extra_'.$field_details[1]] = date('Y-m-d 12:00:00');
4600
                    $form->setDefaults($defaults);
4601
                    if (!$admin_permissions) {
4602
                        if ($field_details[7] == 0)
4603
                            $form->freeze('extra_'.$field_details[1]);
4604
                    }
4605
                    $form->applyFilter('theme', 'trim');
4606
                    break;
4607
                case ExtraField::FIELD_TYPE_DOUBLE_SELECT:
4608
                    foreach ($field_details[9] as $key => $element) {
4609
                        if ($element[2][0] == '*') {
4610
                            $values['*'][$element[0]] = str_replace('*', '', $element[2]);
4611
                        } else {
4612
                            $values[0][$element[0]] = $element[2];
4613
                        }
4614
                    }
4615
4616
                    $group = '';
4617
                    $group[] = $form->createElement('select', 'extra_'.$field_details[1], '', $values[0], '');
4618
                    $group[] = $form->createElement('select', 'extra_'.$field_details[1].'*', '', $values['*'], '');
4619
                    $form->addGroup($group, 'extra_'.$field_details[1], $field_details[3], '&nbsp;');
4620
4621
                    if (!$admin_permissions) {
4622
                        if ($field_details[7] == 0)
4623
                            $form->freeze('extra_'.$field_details[1]);
4624
                    }
4625
4626
                    /* Recoding the selected values for double : if the user has
4627
                    selected certain values, we have to assign them to the
4628
                    correct select form */
4629
                    if (array_key_exists('extra_'.$field_details[1], $extra_data)) {
4630
                        // exploding all the selected values (of both select forms)
4631
                        $selected_values = explode(';', $extra_data['extra_'.$field_details[1]]);
4632
                        $extra_data['extra_'.$field_details[1]] = array();
4633
4634
                        // looping through the selected values and assigning the selected values to either the first or second select form
4635
                        foreach ($selected_values as $key => $selected_value) {
4636
                            if (array_key_exists($selected_value, $values[0])) {
4637
                                $extra_data['extra_'.$field_details[1]]['extra_'.$field_details[1]] = $selected_value;
4638
                            } else {
4639
                                $extra_data['extra_'.$field_details[1]]['extra_'.$field_details[1].'*'] = $selected_value;
4640
                            }
4641
                        }
4642
                    }
4643
                    break;
4644
                case ExtraField::FIELD_TYPE_DIVIDER:
4645
                    $form->addElement('static', $field_details[1], '<br /><strong>'.$field_details[3].'</strong>');
4646
                    break;
4647
                case ExtraField::FIELD_TYPE_TAG:
4648
                    //the magic should be here
4649
                    $user_tags = UserManager::get_user_tags($user_id, $field_details[0]);
4650
4651
                    $tag_list = '';
4652
                    if (is_array($user_tags) && count($user_tags) > 0) {
4653
                        foreach ($user_tags as $tag) {
4654
                            $tag_list .= '<option value="'.$tag['tag'].'" class="selected">'.$tag['tag'].'</option>';
4655
                        }
4656
                    }
4657
4658
                    $multi_select = '<select id="extra_'.$field_details[1].'" name="extra_'.$field_details[1].'">
4659
                                    '.$tag_list.'
4660
                                    </select>';
4661
4662
                    $form->addElement('label', $field_details[3], $multi_select);
4663
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
4664
                    $complete_text = get_lang('StartToType');
4665
                    //if cache is set to true the jquery will be called 1 time
4666
                    $jquery_ready_content = <<<EOF
4667
                    $("#extra_$field_details[1]").fcbkcomplete({
4668
                        json_url: "$url?a=search_tags&field_id=$field_details[0]",
4669
                        cache: false,
4670
                        filter_case: true,
4671
                        filter_hide: true,
4672
                        complete_text:"$complete_text",
4673
                        firstselected: true,
4674
                        //onremove: "testme",
4675
                        //onselect: "testme",
4676
                        filter_selected: true,
4677
                        newel: true
4678
                    });
4679
EOF;
4680
                    break;
4681 View Code Duplication
                case ExtraField::FIELD_TYPE_TIMEZONE:
4682
                    $form->addElement('select', 'extra_'.$field_details[1], $field_details[3], api_get_timezones(), '');
4683
                    if ($field_details[7] == 0)
4684
                        $form->freeze('extra_'.$field_details[1]);
4685
                    break;
4686
                case ExtraField::FIELD_TYPE_SOCIAL_PROFILE:
4687
                    // get the social network's favicon
4688
                    $icon_path = UserManager::get_favicon_from_url($extra_data['extra_'.$field_details[1]], $field_details[4]);
4689
                    // special hack for hi5
4690
                    $leftpad = '1.7';
4691
                    $top = '0.4';
4692
                    $domain = parse_url($icon_path, PHP_URL_HOST);
4693
                    if ($domain == 'www.hi5.com' or $domain == 'hi5.com') {
4694
                        $leftpad = '3';
4695
                        $top = '0';
4696
                    }
4697
                    // print the input field
4698
                    $form->addElement(
4699
                        'text',
4700
                        'extra_'.$field_details[1],
4701
                        $field_details[3],
4702
                        array(
4703
                            'size' => 60,
4704
                            'style' => 'background-image: url(\''.$icon_path.'\'); background-repeat: no-repeat; background-position: 0.4em '.$top.'em; padding-left: '.$leftpad.'em; '
4705
                        )
4706
                    );
4707
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4708
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4709
                    if ($field_details[7] == 0)
4710
                        $form->freeze('extra_'.$field_details[1]);
4711
                    break;
4712
                case ExtraField::FIELD_TYPE_FILE:
4713
                    $extra_field = 'extra_'.$field_details[1];
4714
                    $form->addElement('file', $extra_field, $field_details[3], null, '');
4715
                    if ($extra_file_list = UserManager::build_user_extra_file_list($user_id, $field_details[1], '', true)) {
4716
                        $form->addElement('static', $extra_field . '_list', null, $extra_file_list);
4717
                    }
4718
                    if ($field_details[7] == 0) {
4719
                        $form->freeze($extra_field);
4720
                    }
4721
                    break;
4722 View Code Duplication
                case ExtraField::FIELD_TYPE_MOBILE_PHONE_NUMBER:
4723
                    $form->addElement(
4724
                        'text',
4725
                        'extra_'.$field_details[1],
4726
                        $field_details[3]." (".get_lang('CountryDialCode').")",
4727
                        array('size' => 40, 'placeholder'  => '(xx)xxxxxxxxx')
4728
                    );
4729
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4730
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4731
                    $form->applyFilter('extra_'.$field_details[1], 'mobile_phone_number_filter');
4732
                    $form->addRule(
4733
                        'extra_'.$field_details[1],
4734
                        get_lang('MobilePhoneNumberWrong'),
4735
                        'mobile_phone_number'
4736
                    );
4737
                    if (!$admin_permissions) {
4738
                        if ($field_details[7] == 0) {
4739
                            $form->freeze('extra_'.$field_details[1]);
4740
                        }
4741
                    }
4742
                    break;
4743
            }
4744
        }
4745
        $return = array();
4746
        $return['jquery_ready_content'] = $jquery_ready_content;
4747
        return $return;
4748
    }
4749
4750
    /**
4751
     * @return array
4752
     */
4753
    static function get_user_field_types()
4754
    {
4755
        $types = array();
4756
        $types[self::USER_FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
4757
        $types[self::USER_FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
4758
        $types[self::USER_FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
4759
        $types[self::USER_FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
4760
        $types[self::USER_FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
4761
        $types[self::USER_FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
4762
        $types[self::USER_FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
4763
        $types[self::USER_FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
4764
        $types[self::USER_FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
4765
        $types[self::USER_FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
4766
        $types[self::USER_FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
4767
        $types[self::USER_FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
4768
        $types[self::USER_FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
4769
        $types[self::USER_FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
4770
4771
        return $types;
4772
    }
4773
4774
    /**
4775
     * @param int $userId
4776
     */
4777 View Code Duplication
    static function add_user_as_admin($userId)
4778
    {
4779
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
4780
        $userId = intval($userId);
4781
4782
        if (!self::is_admin($userId)) {
4783
            $sql = "INSERT INTO $table_admin SET user_id = $userId";
4784
            Database::query($sql);
4785
        }
4786
    }
4787
4788
    /**
4789
     * @param int $userId
4790
     */
4791 View Code Duplication
    public static function remove_user_admin($userId)
4792
    {
4793
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
4794
        $userId = intval($userId);
4795
        if (self::is_admin($userId)) {
4796
            $sql = "DELETE FROM $table_admin WHERE user_id = $userId";
4797
            Database::query($sql);
4798
        }
4799
    }
4800
4801
    /**
4802
     * @param string $from
4803
     * @param string $to
4804
     */
4805
    public static function update_all_user_languages($from, $to)
4806
    {
4807
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4808
        $from = Database::escape_string($from);
4809
        $to = Database::escape_string($to);
4810
4811
        if (!empty($to) && !empty($from)) {
4812
            $sql = "UPDATE $table_user SET language = '$to'
4813
                    WHERE language = '$from'";
4814
            Database::query($sql);
4815
        }
4816
    }
4817
4818
    /**
4819
     * Subscribe boss to students
4820
     * 
4821
     * @param int $bossId The boss id
4822
     * @param array $usersId The users array
4823
     * @return int Affected rows
4824
     */
4825
    public static function subscribeBossToUsers($bossId, $usersId)
4826
    {
4827
        return self::subscribeUsersToUser($bossId, $usersId, USER_RELATION_TYPE_BOSS);
4828
    }
4829
4830
    /**
4831
     * Subscribe boss to students
4832
     *
4833
     * @param int $studentId
4834
     * @param array $bossList
4835
     * @return int Affected rows
4836
     */
4837
    public static function subscribeUserToBossList($studentId, $bossList)
4838
    {
4839
        $count = 1;
4840
        if ($bossList) {
4841
            $studentId = (int) $studentId;
4842
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4843
            $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4844
            $sql = "DELETE FROM $userRelUserTable 
4845
                    WHERE user_id = $studentId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4846
            Database::query($sql);
4847
4848
            foreach ($bossList as $bossId) {
4849
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4850
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
4851
4852
                Database::query($sql);
4853
            }
4854
        }
4855
    }
4856
4857
    /**
4858
     * Get users followed by student boss
4859
     * @param int $userId
4860
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
4861
     * @param bool $getOnlyUserId
4862
     * @param bool $getSql
4863
     * @param bool $getCount
4864
     * @param int $from
4865
     * @param int $numberItems
4866
     * @param int $column
4867
     * @param string $direction
4868
     * @param int $active
4869
     * @param string $lastConnectionDate
4870
     * @return array     users
4871
     */
4872 View Code Duplication
    public static function getUsersFollowedByStudentBoss(
4873
        $userId,
4874
        $userStatus = 0,
4875
        $getOnlyUserId = false,
4876
        $getSql = false,
4877
        $getCount = false,
4878
        $from = null,
4879
        $numberItems = null,
4880
        $column = null,
4881
        $direction = null,
4882
        $active = null,
4883
        $lastConnectionDate = null
4884
    ){
4885
        return self::getUsersFollowedByUser(
4886
            $userId,
4887
            $userStatus,
4888
            $getOnlyUserId,
4889
            $getSql,
4890
            $getCount,
4891
            $from,
4892
            $numberItems,
4893
            $column,
4894
            $direction,
4895
            $active,
4896
            $lastConnectionDate,
4897
            STUDENT_BOSS
4898
        );
4899
    }
4900
4901
    /**
4902
     * Get the teacher (users with COURSEMANGER status) list
4903
     * @return array The list
4904
     */
4905
    public static function getTeachersList()
4906
    {
4907
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4908
4909
        $resultData = Database::select('user_id, lastname, firstname, username', $userTable, array(
4910
            'where' => array(
4911
                'status = ?' => COURSEMANAGER
4912
            )
4913
        ));
4914
4915
        foreach ($resultData as &$teacherData) {
4916
            $teacherData['completeName'] = api_get_person_name($teacherData['firstname'], $teacherData['lastname']);
4917
        }
4918
4919
        return $resultData;
4920
    }
4921
4922
    /**
4923
     * @return array
4924
     */
4925 View Code Duplication
    public static function getOfficialCodeGrouped()
4926
    {
4927
        $user = Database::get_main_table(TABLE_MAIN_USER);
4928
        $sql = "SELECT DISTINCT official_code
4929
                FROM $user
4930
                GROUP BY official_code";
4931
        $result = Database::query($sql);
4932
4933
        $values = Database::store_result($result, 'ASSOC');
4934
4935
        $result = array();
4936
        foreach ($values as $value) {
4937
            $result[$value['official_code']] = $value['official_code'];
4938
        }
4939
        return $result;
4940
    }
4941
4942
    /**
4943
     * @param string $officialCode
4944
     * @return array
4945
     */
4946
    public static function getUsersByOfficialCode($officialCode)
4947
    {
4948
        $user = Database::get_main_table(TABLE_MAIN_USER);
4949
        $officialCode = Database::escape_string($officialCode);
4950
4951
        $sql = "SELECT DISTINCT id
4952
                FROM $user
4953
                WHERE official_code = '$officialCode'
4954
                ";
4955
        $result = Database::query($sql);
4956
4957
        $users = array();
4958
        while ($row = Database::fetch_array($result)) {
4959
            $users[] = $row['id'];
4960
        }
4961
        return $users;
4962
    }
4963
4964
    /**
4965
     * Calc the expended time (in seconds) by a user in a course
4966
     * @param int $userId The user id
4967
     * @param int $courseId The course id
4968
     * @param int $sessionId Optional. The session id
4969
     * @param string $from Optional. From date
4970
     * @param string $until Optional. Until date
4971
     * @return int The time
4972
     */
4973
    public static function getTimeSpentInCourses($userId, $courseId, $sessionId = 0, $from = '', $until = '')
4974
    {
4975
        $userId = intval($userId);
4976
        $sessionId = intval($sessionId);
4977
4978
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4979
4980
        $whereConditions = array(
4981
            'user_id = ? ' => $userId,
4982
            'AND c_id = ? ' => $courseId,
4983
            'AND session_id = ? ' => $sessionId
4984
        );
4985
4986 View Code Duplication
        if (!empty($from) && !empty($until)) {
4987
            $whereConditions["AND (login_course_date >= '?' "] = $from;
4988
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
4989
        }
4990
4991
        $trackResult = Database::select(
4992
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
4993
            $trackCourseAccessTable,
4994
            array(
4995
                'where' => $whereConditions
4996
            ), 'first'
4997
        );
4998
4999
        if ($trackResult != false) {
5000
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5001
        }
5002
5003
        return 0;
5004
    }
5005
5006
    /**
5007
     * Get the boss user ID from a followed user id
5008
     * @param $userId
5009
     * @return bool
5010
     */
5011 View Code Duplication
    public static function getFirstStudentBoss($userId)
5012
    {
5013
        $userId = intval($userId);
5014
        if ($userId > 0) {
5015
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5016
            $row = Database::select(
5017
                'DISTINCT friend_user_id AS boss_id',
5018
                $userRelTable,
5019
                array(
5020
                    'where' => array(
5021
                        'user_id = ? AND relation_type = ? LIMIT 1' => array(
5022
                            $userId,
5023
                            USER_RELATION_TYPE_BOSS,
5024
                        )
5025
                    )
5026
                )
5027
            );
5028
            if (!empty($row)) {
5029
5030
                return $row[0]['boss_id'];
5031
            }
5032
        }
5033
5034
        return false;
5035
    }
5036
5037
    /**
5038
     * Get the boss user ID from a followed user id
5039
     * @param $userId
5040
     * @return bool
5041
     */
5042 View Code Duplication
    public static function getStudentBossList($userId)
5043
    {
5044
        $userId = intval($userId);
5045
        if ($userId > 0) {
5046
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5047
            $result = Database::select(
5048
                'DISTINCT friend_user_id AS boss_id',
5049
                $userRelTable,
5050
                array(
5051
                    'where' => array(
5052
                        'user_id = ? AND relation_type = ? ' => array(
5053
                            $userId,
5054
                            USER_RELATION_TYPE_BOSS,
5055
                        )
5056
                    )
5057
                ),
5058
                'all'
5059
            );
5060
5061
            return $result;
5062
        }
5063
5064
        return false;
5065
    }
5066
5067
    /**
5068
     * Get either a Gravatar URL or complete image tag for a specified email address.
5069
     *
5070
     * @param string $email The email address
5071
     * @param string $s Size in pixels, defaults to 80px [ 1 - 2048 ]
5072
     * @param string $d Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
5073
     * @param string $r Maximum rating (inclusive) [ g | pg | r | x ]
5074
     * @param boole $img True to return a complete IMG tag False for just the URL
5075
     * @param array $atts Optional, additional key/value attributes to include in the IMG tag
5076
     * @return String containing either just a URL or a complete image tag
5077
     * @source http://gravatar.com/site/implement/images/php/
5078
     */
5079
    private static function getGravatar(
5080
        $email,
5081
        $s = 80,
5082
        $d = 'mm',
5083
        $r = 'g',
5084
        $img = false,
5085
        $atts = array()
5086
    ) {
5087
        $url = 'http://www.gravatar.com/avatar/';
5088
        if (!empty($_SERVER['HTTPS'])) {
5089
            $url = 'https://secure.gravatar.com/avatar/';
5090
        }
5091
        $url .= md5( strtolower( trim( $email ) ) );
5092
        $url .= "?s=$s&d=$d&r=$r";
5093
        if ( $img ) {
5094
            $url = '<img src="' . $url . '"';
5095
            foreach ( $atts as $key => $val )
5096
                $url .= ' ' . $key . '="' . $val . '"';
5097
            $url .= ' />';
5098
        }
5099
        return $url;
5100
    }
5101
5102
5103
5104
    /**
5105
     * Displays the name of the user and makes the link to the user profile
5106
     * @param array $userInfo
5107
     *
5108
     * @return string
5109
     */
5110
    public static function getUserProfileLink($userInfo)
5111
    {
5112
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5113
            return Display::url($userInfo['complete_name'], $userInfo['profile_url']);
5114
        } else {
5115
            return get_lang('Anonymous');
5116
        }
5117
    }
5118
5119
    /**
5120
     * Displays the name of the user and makes the link to the user profile
5121
     *
5122
     * @param $userInfo
5123
     *
5124
     * @return string
5125
     */
5126
    public static function getUserProfileLinkWithPicture($userInfo)
5127
    {
5128
        return Display::url(Display::img($userInfo['avatar']), $userInfo['profile_url']);
5129
    }
5130
5131
    /**
5132
     * Get users whose name matches $firstname and $lastname
5133
     * @param string $firstname Firstname to search
5134
     * @param string $lastname Lastname to search
5135
     * @return array The user list
5136
     */
5137 View Code Duplication
    public static function getUserByName($firstname, $lastname)
5138
    {
5139
        $firstname = Database::escape_string($firstname);
5140
        $lastname = Database::escape_string($lastname);
5141
5142
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5143
5144
        $sql = <<<SQL
5145
            SELECT id, username, lastname, firstname
5146
            FROM $userTable
5147
            WHERE firstname LIKE '$firstname%' AND
5148
                lastname LIKE '$lastname%'
5149
SQL;
5150
5151
        $result = Database::query($sql);
5152
5153
        $users = [];
5154
5155
        while ($resultData = Database::fetch_object($result)) {
5156
            $users[] = $resultData;
5157
        }
5158
5159
        return $users;
5160
    }
5161
5162
    /**
5163
     * @param int $optionSelected
5164
     * @return string
5165
     */
5166
    public static function getUserSubscriptionTab($optionSelected = 1)
5167
    {
5168
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5169
        if (($allowAdmin == 'true' && api_is_allowed_to_edit()) ||
5170
            api_is_platform_admin()
5171
        ) {
5172
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5173
5174
            $headers = [
5175
                [
5176
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5177
                    'content' => get_lang('Students'),
5178
                ],
5179
                [
5180
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5181
                    'content' => get_lang('Teachers'),
5182
                ],
5183
                /*[
5184
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5185
                    'content' => get_lang('Students'),
5186
                ],
5187
                [
5188
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5189
                    'content' => get_lang('Teachers'),
5190
                ],*/
5191
                [
5192
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5193
                    'content' => get_lang('Groups'),
5194
                ],
5195
                [
5196
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5197
                    'content' => get_lang('Classes'),
5198
                ],
5199
            ];
5200
5201
            return Display::tabsOnlyLink($headers, $optionSelected);
5202
        }
5203
    }
5204
5205
}
5206