Passed
Push — 1.10.x ( 44706e...767d99 )
by
unknown
56:54
created

UserManager::disable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 8
rs 9.4285
cc 2
eloc 5
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 View Code Duplication
                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 = $_configuration['root_web'];
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
        return $return;
463
    }
464
465
    /**
466
     * Can user be deleted? This function checks whether there's a course
467
     * in which the given user is the
468
     * only course administrator. If that is the case, the user can't be
469
     * deleted because the course would remain without a course admin.
470
     * @param int $user_id The user id
471
     * @return boolean true if user can be deleted
472
     * @assert (null) === false
473
     * @assert (-1) === false
474
     * @assert ('abc') === false
475
     */
476
    public static function can_delete_user($user_id)
477
    {
478
        $deny = api_get_configuration_value('deny_delete_users');
479
480
        if ($deny) {
481
            return false;
482
        }
483
484
        $table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
485
        if ($user_id != strval(intval($user_id))) {
486
            return false;
487
        }
488
        if ($user_id === false) {
489
            return false;
490
        }
491
        $sql = "SELECT * FROM $table_course_user
492
                WHERE status = 1 AND user_id = ".$user_id;
493
        $res = Database::query($sql);
494
        while ($course = Database::fetch_object($res)) {
495
            $sql = "SELECT id FROM $table_course_user
496
                    WHERE status=1 AND c_id = " . intval($course->c_id);
497
            $res2 = Database::query($sql);
498
            if (Database::num_rows($res2) == 1) {
499
500
                return false;
501
            }
502
        }
503
504
        return true;
505
    }
506
507
    /**
508
     * Delete a user from the platform, and all its belongings. This is a
509
     * very dangerous function that should only be accessible by
510
     * super-admins. Other roles should only be able to disable a user,
511
     * which removes access to the platform but doesn't delete anything.
512
     * @param int The ID of th user to be deleted
513
     * @return boolean true if user is successfully deleted, false otherwise
514
     * @assert (null) === false
515
     * @assert ('abc') === false
516
     */
517
    public static function delete_user($user_id)
518
    {
519
        if ($user_id != strval(intval($user_id))) {
520
            return false;
521
        }
522
523
        if ($user_id === false) {
524
            return false;
525
        }
526
527
        if (!self::can_delete_user($user_id)) {
528
            return false;
529
        }
530
531
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
532
        $usergroup_rel_user = Database :: get_main_table(TABLE_USERGROUP_REL_USER);
533
        $table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
534
        $table_course = Database :: get_main_table(TABLE_MAIN_COURSE);
535
        $table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
536
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
537
        $table_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
538
        $table_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
539
        $table_group = Database :: get_course_table(TABLE_GROUP_USER);
540
        $table_work = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
541
542
        // Unsubscribe the user from all groups in all his courses
543
        $sql = "SELECT c.id FROM $table_course c, $table_course_user cu
544
                WHERE
545
                    cu.user_id = '".$user_id."' AND
546
                    relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
547
                    c.id = cu.c_id";
548
549
        $res = Database::query($sql);
550
        while ($course = Database::fetch_object($res)) {
551
            $sql = "DELETE FROM $table_group
552
                    WHERE c_id = {$course->id} AND user_id = $user_id";
553
            Database::query($sql);
554
        }
555
556
        // Unsubscribe user from usergroup_rel_user
557
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
558
        Database::query($sql);
559
560
        // Unsubscribe user from all courses
561
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
562
        Database::query($sql);
563
564
        // Unsubscribe user from all courses in sessions
565
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
566
        Database::query($sql);
567
568
        // If the user was added as a id_coach then set the current admin as coach see BT#
569
        $currentUserId = api_get_user_id();
570
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
571
                WHERE id_coach = '".$user_id."'";
572
        Database::query($sql);
573
574
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
575
                WHERE session_admin_id = '".$user_id."'";
576
        Database::query($sql);
577
578
        // Unsubscribe user from all sessions
579
        $sql = "DELETE FROM $table_session_user
580
                WHERE user_id = '".$user_id."'";
581
        Database::query($sql);
582
583
        // Delete user picture
584
        /* TODO: Logic about api_get_setting('split_users_upload_directory') == 'true'
585
        a user has 4 different sized photos to be deleted. */
586
        $user_info = api_get_user_info($user_id);
587
588
        if (strlen($user_info['picture_uri']) > 0) {
589
            $path = self::getUserPathById($user_id, 'system');
590
            $img_path = $path.$user_info['picture_uri'];
591
            if (file_exists($img_path)) {
592
                unlink($img_path);
593
            }
594
        }
595
596
        // Delete the personal course categories
597
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
598
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
599
        Database::query($sql);
600
601
        // Delete user from the admin table
602
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
603
        Database::query($sql);
604
605
        // Delete the personal agenda-items from this user
606
        $agenda_table = Database :: get_main_table(TABLE_PERSONAL_AGENDA);
607
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
608
        Database::query($sql);
609
610
        $gradebook_results_table = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
611
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
612
        Database::query($sql);
613
614
        $extraFieldValue = new ExtraFieldValue('user');
615
        $extraFieldValue->deleteValuesByItem($user_id);
616
617
        UrlManager::deleteUserFromAllUrls($user_id);
618
619
        if (api_get_setting('allow_social_tool') == 'true') {
620
            $userGroup = new UserGroup();
621
            //Delete user from portal groups
622
            $group_list = $userGroup->get_groups_by_user($user_id);
623
            if (!empty($group_list)) {
624
                foreach ($group_list as $group_id => $data) {
625
                    $userGroup->delete_user_rel_group($user_id, $group_id);
626
                }
627
            }
628
629
            // Delete user from friend lists
630
            SocialManager::remove_user_rel_user($user_id, true);
631
        }
632
633
        // Removing survey invitation
634
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
635
636
        // Delete students works
637
        $sql = "DELETE FROM $table_work WHERE user_id = $user_id AND c_id <> 0";
638
        Database::query($sql);
639
640
        $sql = "UPDATE c_item_property SET to_user_id = NULL
641
                WHERE to_user_id = '".$user_id."'";
642
        Database::query($sql);
643
644
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
645
                WHERE insert_user_id = '".$user_id."'";
646
        Database::query($sql);
647
648
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
649
                WHERE lastedit_user_id = '".$user_id."'";
650
        Database::query($sql);
651
652
653
654
655
        // Delete user from database
656
        $sql = "DELETE FROM $table_user WHERE id = '".$user_id."'";
657
        Database::query($sql);
658
659
        // Add event to system log
660
        $user_id_manager = api_get_user_id();
661
662
        Event::addEvent(
663
            LOG_USER_DELETE,
664
            LOG_USER_ID,
665
            $user_id,
666
            api_get_utc_datetime(),
667
            $user_id_manager
668
        );
669
670
        Event::addEvent(
671
            LOG_USER_DELETE,
672
            LOG_USER_OBJECT,
673
            $user_info,
674
            api_get_utc_datetime(),
675
            $user_id_manager
676
        );
677
678
        return true;
679
    }
680
681
    /**
682
     * Deletes users completely. Can be called either as:
683
     * - UserManager :: delete_users(1, 2, 3); or
684
     * - UserManager :: delete_users(array(1, 2, 3));
685
     * @param array|int $ids
686
     * @return boolean  True if at least one user was successfuly deleted. False otherwise.
687
     * @author Laurent Opprecht
688
     * @uses UserManager::delete_user() to actually delete each user
689
     * @assert (null) === false
690
     * @assert (-1) === false
691
     * @assert (array(-1)) === false
692
     */
693
    static function delete_users($ids = array())
694
    {
695
        $result = false;
696
        $ids = is_array($ids) ? $ids : func_get_args();
697
        if (!is_array($ids) or count($ids) == 0) { return false; }
698
        $ids = array_map('intval', $ids);
699
        foreach ($ids as $id) {
700
            if (empty($id) or $id < 1) { continue; }
701
            $deleted = self::delete_user($id);
702
            $result = $deleted || $result;
703
        }
704
705
        return $result;
706
    }
707
708
    /**
709
     * Disable users. Can be called either as:
710
     * - UserManager :: deactivate_users(1, 2, 3);
711
     * - UserManager :: deactivate_users(array(1, 2, 3));
712
     * @param array|int $ids
713
     * @return boolean
714
     * @author Laurent Opprecht
715
     * @assert (null) === false
716
     * @assert (array(-1)) === false
717
     */
718 View Code Duplication
    static function deactivate_users($ids = array())
719
    {
720
        if (empty($ids)) {
721
            return false;
722
        }
723
724
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
725
726
        $ids = is_array($ids) ? $ids : func_get_args();
727
        $ids = array_map('intval', $ids);
728
        $ids = implode(',', $ids);
729
730
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
731
        $r = Database::query($sql);
732
        if ($r !== false) {
733
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
734
        }
735
        return $r;
736
    }
737
738
    /**
739
     * Enable users. Can be called either as:
740
     * - UserManager :: activate_users(1, 2, 3);
741
     * - UserManager :: activate_users(array(1, 2, 3));
742
     * @param array|int IDs of the users to enable
743
     * @return boolean
744
     * @author Laurent Opprecht
745
     * @assert (null) === false
746
     * @assert (array(-1)) === false
747
     */
748 View Code Duplication
    static function activate_users($ids = array())
749
    {
750
        if (empty($ids)) {
751
            return false;
752
        }
753
754
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
755
756
        $ids = is_array($ids) ? $ids : func_get_args();
757
        $ids = array_map('intval', $ids);
758
        $ids = implode(',', $ids);
759
760
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
761
        $r = Database::query($sql);
762
        if ($r !== false) {
763
            Event::addEvent(LOG_USER_ENABLE,LOG_USER_ID,$ids);
764
        }
765
        return $r;
766
    }
767
768
    /**
769
     * Update user information with new openid
770
     * @param int $user_id
771
     * @param string $openid
772
     * @return boolean true if the user information was updated
773
     * @assert (false,'') === false
774
     * @assert (-1,'') === false
775
     */
776
    public static function update_openid($user_id, $openid)
777
    {
778
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
779
        if ($user_id != strval(intval($user_id)))
780
            return false;
781
        if ($user_id === false)
782
            return false;
783
        $sql = "UPDATE $table_user SET
784
                openid='".Database::escape_string($openid)."'";
785
        $sql .= " WHERE id= $user_id";
786
        return Database::query($sql);
787
    }
788
789
    /**
790
     * Update user information with all the parameters passed to this function
791
     * @param int The ID of the user to be updated
792
     * @param string The user's firstname
793
     * @param string The user's lastname
794
     * @param string The user's username (login)
795
     * @param string The user's password
796
     * @param string The authentication source (default: "platform")
797
     * @param string The user's e-mail address
798
     * @param int The user's status
799
     * @param string The user's official code (usually just an internal institutional code)
800
     * @param string The user's phone number
801
     * @param string The user's picture URL (internal to the Chamilo directory)
802
     * @param int The user ID of the person who registered this user (optional, defaults to null)
803
     * @param int The department of HR in which the user is registered (optional, defaults to 0)
804
     * @param array A series of additional fields to add to this user as extra fields (optional, defaults to null)
805
     * @return boolean|integer False on error, or the user ID if the user information was updated
806
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
807
     */
808
    public static function update_user(
809
        $user_id,
810
        $firstname,
811
        $lastname,
812
        $username,
813
        $password = null,
814
        $auth_source = null,
815
        $email,
816
        $status,
817
        $official_code,
818
        $phone,
819
        $picture_uri,
820
        $expiration_date,
821
        $active,
822
        $creator_id = null,
823
        $hr_dept_id = 0,
824
        $extra = null,
825
        $language = 'english',
826
        $encrypt_method = '',
827
        $send_email = false,
828
        $reset_password = 0
829
    ) {
830
        $hook = HookUpdateUser::create();
831
        if (!empty($hook)) {
832
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_PRE);
833
        }
834
        global $_configuration;
835
        $original_password = $password;
836
837
        if (empty($user_id)) {
838
            return false;
839
        }
840
        $user_info = api_get_user_info($user_id, false, true);
841
842
        if ($reset_password == 0) {
843
            $password = null;
844
            $auth_source = $user_info['auth_source'];
845
        } elseif ($reset_password == 1) {
846
            $original_password = $password = api_generate_password();
847
            $auth_source = PLATFORM_AUTH_SOURCE;
848
        } elseif ($reset_password == 2) {
849
            $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...
850
            $auth_source = PLATFORM_AUTH_SOURCE;
851
        } elseif ($reset_password == 3) {
852
            $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...
853
            $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...
854
        }
855
856
        if ($user_id != strval(intval($user_id))) {
857
            return false;
858
        }
859
860
        if ($user_id === false) {
861
            return false;
862
        }
863
864
        //Checking the user language
865
        $languages = api_get_languages();
866
        if (!in_array($language, $languages['folder'])) {
867
            $language = api_get_setting('platformLanguage');
868
        }
869
870
        $change_active = 0;
871
        if ($user_info['active'] != $active) {
872
            $change_active = 1;
873
        }
874
875
        $userManager = self::getManager();
876
877
        /** @var Chamilo\UserBundle\Entity\User $user */
878
        $user = self::getRepository()->find($user_id);
879
880
        if (empty($user)) {
881
            return false;
882
        }
883
884
        if (!empty($expiration_date)) {
885
            $expiration_date = api_get_utc_datetime($expiration_date);
886
            $expiration_date = new \DateTime(
887
                $expiration_date,
888
                new DateTimeZone('UTC')
889
            );
890
        }
891
892
        $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...
893
            ->setLastname($lastname)
894
            ->setFirstname($firstname)
895
            ->setUsername($username)
896
            ->setStatus($status)
897
            ->setAuthSource($auth_source)
898
            ->setLanguage($language)
899
            ->setEmail($email)
900
            ->setOfficialCode($official_code)
901
            ->setPhone($phone)
902
            ->setPictureUri($picture_uri)
903
            ->setExpirationDate($expiration_date)
904
            ->setActive($active)
905
            ->setHrDeptId($hr_dept_id)
906
        ;
907
908
        if (!is_null($password)) {
909
            $user->setPlainPassword($password);
910
        }
911
912
        $userManager->updateUser($user, true);
913
914
        if ($change_active == 1) {
915
            if ($active == 1) {
916
                $event_title = LOG_USER_ENABLE;
917
            } else {
918
                $event_title = LOG_USER_DISABLE;
919
            }
920
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
921
        }
922
923 View Code Duplication
        if (is_array($extra) && count($extra) > 0) {
924
            $res = true;
925
            foreach ($extra as $fname => $fvalue) {
926
                $res = $res && self::update_extra_field_value(
927
                    $user_id,
928
                    $fname,
929
                    $fvalue
930
                );
931
            }
932
        }
933
934
        if (!empty($email) && $send_email) {
935
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
936
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('YourReg').' '.api_get_setting('siteName');
937
            $sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);
938
            $email_admin = api_get_setting('emailAdministrator');
939
940
            if (api_is_multiple_url_enabled()) {
941
                $access_url_id = api_get_current_access_url_id();
942
                if ($access_url_id != -1) {
943
                    $url = api_get_access_url($access_url_id);
944
                    $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');
945
                }
946
            } else {
947
                $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');
948
            }
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
        return $result;
1273
    }
1274
1275
    /**
1276
     * Get a list of users of which the given conditions match with an = 'cond'
1277
     * @param array $conditions a list of condition (exemple : status=>STUDENT)
1278
     * @param array $order_by a list of fields on which sort
1279
     * @return array An array with all users of the platform.
1280
     * @todo optional course code parameter, optional sorting parameters...
1281
     * @todo security filter order by
1282
     */
1283
    public static function get_user_list($conditions = array(), $order_by = array(), $limit_from = false, $limit_to = false)
1284
    {
1285
        $user_table = Database :: get_main_table(TABLE_MAIN_USER);
1286
        $return_array = array();
1287
        $sql_query = "SELECT * FROM $user_table";
1288
        if (count($conditions) > 0) {
1289
            $sql_query .= ' WHERE ';
1290
            foreach ($conditions as $field => $value) {
1291
                $field = Database::escape_string($field);
1292
                $value = Database::escape_string($value);
1293
                $sql_query .= "$field = '$value'";
1294
            }
1295
        }
1296 View Code Duplication
        if (count($order_by) > 0) {
1297
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1298
        }
1299
1300
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1301
            $limit_from = intval($limit_from);
1302
            $limit_to = intval($limit_to);
1303
            $sql_query .= " LIMIT $limit_from, $limit_to";
1304
        }
1305
        $sql_result = Database::query($sql_query);
1306
        while ($result = Database::fetch_array($sql_result)) {
1307
            $return_array[] = $result;
1308
        }
1309
        return $return_array;
1310
    }
1311
1312
    /**
1313
     * Get a list of users of which the given conditions match with a LIKE '%cond%'
1314
     * @param array $conditions a list of condition (exemple : status=>STUDENT)
1315
     * @param array $order_by a list of fields on which sort
1316
     * @return array An array with all users of the platform.
1317
     * @todo optional course code parameter, optional sorting parameters...
1318
     * @todo security filter order_by
1319
     */
1320
    public static function get_user_list_like($conditions = array(), $order_by = array(), $simple_like = false, $condition = 'AND')
1321
    {
1322
        $user_table = Database :: get_main_table(TABLE_MAIN_USER);
1323
        $return_array = array();
1324
        $sql_query = "SELECT * FROM $user_table";
1325
        if (count($conditions) > 0) {
1326
            $sql_query .= ' WHERE ';
1327
            $temp_conditions = array();
1328
            foreach ($conditions as $field => $value) {
1329
                $field = Database::escape_string($field);
1330
                $value = Database::escape_string($value);
1331 View Code Duplication
                if ($simple_like) {
1332
                    $temp_conditions[] = $field." LIKE '$value%'";
1333
                } else {
1334
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1335
                }
1336
            }
1337
            if (!empty($temp_conditions)) {
1338
                $sql_query .= implode(' '.$condition.' ', $temp_conditions);
1339
            }
1340
        }
1341 View Code Duplication
        if (count($order_by) > 0) {
1342
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by), null, false);
1343
        }
1344
        $sql_result = Database::query($sql_query);
1345
        while ($result = Database::fetch_array($sql_result)) {
1346
            $return_array[] = $result;
1347
        }
1348
        return $return_array;
1349
    }
1350
1351
    /**
1352
     * Get user picture URL or path from user ID (returns an array).
1353
     * The return format is a complete path, enabling recovery of the directory
1354
     * with dirname() or the file with basename(). This also works for the
1355
     * functions dealing with the user's productions, as they are located in
1356
     * the same directory.
1357
     * @param   integer   $id User ID
1358
     * @param   string    $type Type of path to return (can be 'system', 'web')
1359
     * @param   array $userInfo user information to avoid query the DB
1360
     * returns the /main/img/unknown.jpg image set it at true
1361
     *
1362
     * @return    array     Array of 2 elements: 'dir' and 'file' which contain
1363
     * the dir and file as the name implies if image does not exist it will
1364
     * return the unknow image if anonymous parameter is true if not it returns an empty array
1365
     */
1366
    public static function get_user_picture_path_by_id($id, $type = 'web', $userInfo = [])
1367
    {
1368
        switch ($type) {
1369
            case 'system': // Base: absolute system path.
1370
                $base = api_get_path(SYS_CODE_PATH);
1371
                break;
1372
            case 'web': // Base: absolute web path.
1373
            default:
1374
                $base = api_get_path(WEB_CODE_PATH);
1375
                break;
1376
        }
1377
1378
        $anonymousPath = array(
1379
            'dir' => $base.'img/',
1380
            'file' => 'unknown.jpg',
1381
            'email' => '',
1382
        );
1383
1384
        if (empty($id) || empty($type)) {
1385
            return $anonymousPath;
1386
        }
1387
1388
        $id = intval($id);
1389 View Code Duplication
        if (empty($userInfo)) {
1390
            $user_table = Database:: get_main_table(TABLE_MAIN_USER);
1391
            $sql = "SELECT email, picture_uri FROM $user_table
1392
                    WHERE id=".$id;
1393
            $res = Database::query($sql);
1394
1395
            if (!Database::num_rows($res)) {
1396
                return $anonymousPath;
1397
            }
1398
            $user = Database::fetch_array($res);
1399
        } else {
1400
            $user = $userInfo;
1401
        }
1402
1403
        $pictureFilename = trim($user['picture_uri']);
1404
1405
        $dir = self::getUserPathById($id, $type);
1406
1407
        return array(
1408
            'dir' => $dir,
1409
            'file' => $pictureFilename,
1410
            'email' => $user['email'],
1411
        );
1412
    }
1413
1414
    /**
1415
     * Get user path from user ID (returns an array).
1416
     * The return format is a complete path to a folder ending with "/"
1417
     * In case the first level of subdirectory of users/ does not exist, the
1418
     * function will attempt to create it. Probably not the right place to do it
1419
     * but at least it avoids headaches in many other places.
1420
     * @param   integer $id User ID
1421
     * @param   string  $type Type of path to return (can be 'system', 'web', 'rel', 'last')
1422
     * @return  string  User folder path (i.e. /var/www/chamilo/app/upload/users/1/1/)
1423
     */
1424
    public static function getUserPathById($id, $type)
1425
    {
1426
        $id = intval($id);
1427
        if (!$id) {
1428
            return null;
1429
        }
1430
1431
        $userPath = "users/$id/";
1432
        if (api_get_setting('split_users_upload_directory') === 'true') {
1433
            $userPath = 'users/'.substr((string) $id, 0, 1).'/'.$id.'/';
1434
            // In exceptional cases, on some portals, the intermediate base user
1435
            // directory might not have been created. Make sure it is before
1436
            // going further.
1437
            $rootPath = api_get_path(SYS_UPLOAD_PATH) . 'users/' . substr((string) $id, 0, 1);
1438
            if (!is_dir($rootPath)) {
1439
                $perm = api_get_permissions_for_new_directories();
1440
                try {
1441
                    mkdir($rootPath, $perm);
1442
                } catch (Exception $e) {
1443
                    //
1444
                }
1445
            }
1446
        }
1447
        switch ($type) {
1448
            case 'system': // Base: absolute system path.
1449
                $userPath = api_get_path(SYS_UPLOAD_PATH).$userPath;
1450
                break;
1451
            case 'web': // Base: absolute web path.
1452
                $userPath = api_get_path(WEB_UPLOAD_PATH).$userPath;
1453
                break;
1454
            case 'rel': // Relative to the document root (e.g. app/upload/users/1/13/)
1455
                $userPath = api_get_path(REL_UPLOAD_PATH).$userPath;
1456
                break;
1457
            case 'last': // Only the last part starting with users/
1458
                break;
1459
        }
1460
1461
        return $userPath;
1462
    }
1463
1464
    /**
1465
     * Gets the current user image
1466
     * @param string $user_id
1467
     * @param int $size it can be USER_IMAGE_SIZE_SMALL,
1468
     * USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1469
     * @param bool $addRandomId
1470
     * @param array $userInfo to avoid query the DB
1471
     *
1472
     * @return string
1473
     */
1474
    public static function getUserPicture(
1475
        $user_id,
1476
        $size = USER_IMAGE_SIZE_MEDIUM,
1477
        $addRandomId = true,
1478
        $userInfo = []
1479
    ) {
1480
        $imageWebPath = self::get_user_picture_path_by_id($user_id, 'web', $userInfo);
1481
        $pictureWebFile = $imageWebPath['file'];
1482
        $pictureWebDir = $imageWebPath['dir'];
1483
1484
        $pictureAnonymousSize = '128';
1485
        $gravatarSize = 22;
1486
        $realSizeName = 'small_';
1487
1488
        switch ($size) {
1489
            case USER_IMAGE_SIZE_SMALL:
1490
                $pictureAnonymousSize = '22';
1491
                $realSizeName = 'small_';
1492
                $gravatarSize = 22;
1493
                break;
1494
            case USER_IMAGE_SIZE_MEDIUM:
1495
                $pictureAnonymousSize = '64';
1496
                $realSizeName = 'medium_';
1497
                $gravatarSize = 50;
1498
                break;
1499
            case USER_IMAGE_SIZE_ORIGINAL:
1500
                $pictureAnonymousSize = '128';
1501
                $realSizeName = '';
1502
                $gravatarSize = 108;
1503
                break;
1504
            case USER_IMAGE_SIZE_BIG:
1505
                $pictureAnonymousSize = '128';
1506
                $realSizeName = 'big_';
1507
                $gravatarSize = 200;
1508
                break;
1509
        }
1510
1511
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1512
1513
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1514
1515
        if ($pictureWebFile == 'unknown.jpg' || empty($pictureWebFile)) {
1516
1517
            if ($gravatarEnabled === 'true') {
1518
                $file = self::getGravatar(
1519
                    $imageWebPath['email'],
1520
                    $gravatarSize,
1521
                    api_get_setting('gravatar_type')
1522
                );
1523
1524
                if ($addRandomId) {
1525
                    $file .= '&rand='.uniqid();
1526
                }
1527
1528
                return $file;
1529
            }
1530
1531
            return $anonymousPath;
1532
        }
1533
1534
        $pictureSysPath = self::get_user_picture_path_by_id($user_id, 'system');
1535
1536
        $file = $pictureSysPath['dir'].$realSizeName.$pictureWebFile;
1537
        $picture = '';
1538
        if (file_exists($file)) {
1539
            $picture = $pictureWebDir.$realSizeName.$pictureWebFile;
1540
        } else {
1541
            $file = $pictureSysPath['dir'].$pictureWebFile;
1542
            if (file_exists($file) && !is_dir($file)) {
1543
                $picture = $pictureWebFile['dir'].$pictureWebFile;
1544
            }
1545
        }
1546
1547
        if (empty($picture)) {
1548
            return $anonymousPath;
1549
        }
1550
1551
        if ($addRandomId) {
1552
            $picture .= '?rand='.uniqid();
1553
        }
1554
1555
        return $picture;
1556
    }
1557
1558
    /**
1559
     * Creates new user photos in various sizes of a user, or deletes user photos.
1560
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
1561
     * @param   int $user_id The user internal identification number.
1562
     * @param   string $file The common file name for the newly created photos.
1563
     *                       It will be checked and modified for compatibility with the file system.
1564
     *                       If full name is provided, path component is ignored.
1565
     *                       If an empty name is provided, then old user photos are deleted only,
1566
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1567
     * @param   string $source_file The full system name of the image from which user photos will be created.
1568
     * @param   string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1569
     * @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...
1570
     * When deletion is requested returns empty string. In case of internal error or negative validation returns FALSE.
1571
     */
1572
    public static function update_user_picture($user_id, $file = null, $source_file = null, $cropParameters)
1573
    {
1574
        if (empty($user_id)) {
1575
            return false;
1576
        }
1577
        $delete = empty($file);
1578
        if (empty($source_file)) {
1579
            $source_file = $file;
1580
        }
1581
1582
        // User-reserved directory where photos have to be placed.
1583
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1584
1585
        $path = $path_info['dir'];
1586
        // If this directory does not exist - we create it.
1587
        if (!file_exists($path)) {
1588
            mkdir($path, api_get_permissions_for_new_directories(), true);
1589
        }
1590
1591
        // The old photos (if any).
1592
        $old_file = $path_info['file'];
1593
1594
        // Let us delete them.
1595 View Code Duplication
        if (!empty($old_file)) {
1596
            if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE) {
1597
                $prefix = 'saved_'.date('Y_m_d_H_i_s').'_'.uniqid('').'_';
1598
                @rename($path.'small_'.$old_file, $path.$prefix.'small_'.$old_file);
1599
                @rename($path.'medium_'.$old_file, $path.$prefix.'medium_'.$old_file);
1600
                @rename($path.'big_'.$old_file, $path.$prefix.'big_'.$old_file);
1601
                @rename($path.$old_file, $path.$prefix.$old_file);
1602
            } else {
1603
                @unlink($path.'small_'.$old_file);
1604
                @unlink($path.'medium_'.$old_file);
1605
                @unlink($path.'big_'.$old_file);
1606
                @unlink($path.$old_file);
1607
            }
1608
        }
1609
1610
        // Exit if only deletion has been requested. Return an empty picture name.
1611
        if ($delete) {
1612
            return '';
1613
        }
1614
1615
        // Validation 2.
1616
        $allowed_types = api_get_supported_image_extensions();
1617
        $file = str_replace('\\', '/', $file);
1618
        $filename = (($pos = strrpos($file, '/')) !== false) ? substr($file, $pos + 1) : $file;
1619
        $extension = strtolower(substr(strrchr($filename, '.'), 1));
1620
        if (!in_array($extension, $allowed_types)) {
1621
            return false;
1622
        }
1623
1624
        // This is the common name for the new photos.
1625 View Code Duplication
        if (KEEP_THE_NAME_WHEN_CHANGE_IMAGE && !empty($old_file)) {
1626
            $old_extension = strtolower(substr(strrchr($old_file, '.'), 1));
1627
            $filename = in_array($old_extension, $allowed_types) ? substr($old_file, 0, -strlen($old_extension)) : $old_file;
1628
            $filename = (substr($filename, -1) == '.') ? $filename.$extension : $filename.'.'.$extension;
1629
        } else {
1630
            $filename = api_replace_dangerous_char($filename);
1631
            if (PREFIX_IMAGE_FILENAME_WITH_UID) {
1632
                $filename = uniqid('').'_'.$filename;
1633
            }
1634
            // We always prefix user photos with user ids, so on setting
1635
            // api_get_setting('split_users_upload_directory') === 'true'
1636
            // the correspondent directories to be found successfully.
1637
            $filename = $user_id.'_'.$filename;
1638
        }
1639
1640
        //Crop the image to adjust 1:1 ratio
1641
        $image = new Image($source_file);
1642
        $image->crop($cropParameters);
1643
1644
        // Storing the new photos in 4 versions with various sizes.
1645
1646
        $small = new Image($source_file);
1647
        $small->resize(22);
1648
        $small->send_image($path.'small_'.$filename);
1649
        $medium = new Image($source_file);
1650
        $medium->resize(85);
1651
        $medium->send_image($path.'medium_'.$filename);
1652
        $normal = new Image($source_file);
1653
        $normal->resize(200);
1654
        $normal->send_image($path.$filename);
1655
1656
        $big = new Image($source_file); // This is the original picture.
1657
        $big->send_image($path.'big_'.$filename);
1658
1659
        $result = $small && $medium && $normal && $big;
1660
1661
        return $result ? $filename : false;
1662
    }
1663
1664
    /**
1665
     * Update User extra field file type into {user_folder}/{$extra_field}
1666
     * @param int $user_id          The user internal identification number
1667
     * @param string $extra_field   The $extra_field The extra field name
1668
     * @param null $file            The filename
1669
     * @param null $source_file     The temporal filename
1670
     * @return bool|null            return filename if success, but false
1671
     */
1672
    public static function update_user_extra_file($user_id, $extra_field = '', $file = null, $source_file = null)
1673
    {
1674
        // Add Filter
1675
        $source_file = Security::filter_filename($source_file);
1676
        $file = Security::filter_filename($file);
1677
1678
        if (empty($user_id)) {
1679
            return false;
1680
        }
1681
1682
        if (empty($source_file)) {
1683
            $source_file = $file;
1684
        }
1685
1686
        // User-reserved directory where extra file have to be placed.
1687
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1688
        $path = $path_info['dir'];
1689
        if (!empty($extra_field)) {
1690
            $path .= $extra_field . '/';
1691
        }
1692
        // If this directory does not exist - we create it.
1693
        if (!file_exists($path)) {
1694
            @mkdir($path, api_get_permissions_for_new_directories(), true);
1695
        }
1696
1697
        if (filter_extension($file)) {
1698
            if (@move_uploaded_file($source_file,$path.$file)) {
1699
                if ($extra_field) {
1700
                    return $extra_field.'/'.$file;
1701
                } else {
1702
                    return $file;
1703
                }
1704
            }
1705
        }
1706
        return false; // this should be returned if anything went wrong with the upload
1707
    }
1708
1709
1710
    /**
1711
     * Deletes user photos.
1712
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php
1713
     * @param int $user_id            The user internal identitfication number.
1714
     * @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...
1715
     */
1716
    public static function delete_user_picture($user_id)
1717
    {
1718
        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...
1719
    }
1720
1721
    /**
1722
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
1723
     * doesn't have any.
1724
     *
1725
     * If there has been a request to remove a production, the function will return
1726
     * without building the list unless forced to do so by the optional second
1727
     * parameter. This increases performance by avoiding to read through the
1728
     * productions on the filesystem before the removal request has been carried
1729
     * out because they'll have to be re-read afterwards anyway.
1730
     *
1731
     * @param    int $user_id    User id
1732
     * @param    $force    Optional parameter to force building after a removal request
1733
     *
1734
     * @return    A string containing the XHTML code to dipslay the production list, or FALSE
1735
     */
1736
    public static function build_production_list($user_id, $force = false, $showdelete = false)
1737
    {
1738
        if (!$force && !empty($_POST['remove_production'])) {
1739
            return true; // postpone reading from the filesystem
1740
        }
1741
        $productions = self::get_user_productions($user_id);
1742
1743
        if (empty($productions)) {
1744
            return false;
1745
        }
1746
1747
        $production_path = self::get_user_picture_path_by_id($user_id, 'web');
1748
        $production_dir = $production_path['dir'];
1749
        $del_image = Display::returnIconPath('delete.png');
1750
        $add_image = Display::returnIconPath('archive.png');
1751
        $del_text = get_lang('Delete');
1752
        $production_list = '';
1753
        if (count($productions) > 0) {
1754
            $production_list = '<div class="files-production"><ul id="productions">';
1755
            foreach ($productions as $file) {
1756
                $production_list .= '<li><img src="'.$add_image.'" /><a href="'.$production_dir.urlencode($file).'" target="_blank">'.htmlentities($file).'</a>';
1757 View Code Duplication
                if ($showdelete) {
1758
                    $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>';
1759
                }
1760
            }
1761
            $production_list .= '</ul></div>';
1762
        }
1763
1764
        return $production_list;
1765
    }
1766
1767
    /**
1768
     * Returns an array with the user's productions.
1769
     *
1770
     * @param    $user_id    User id
1771
     * @return   array  An array containing the user's productions
1772
     */
1773
    public static function get_user_productions($user_id)
1774
    {
1775
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
1776
        $production_repository = $production_path['dir'];
1777
        $productions = array();
1778
1779
        if (is_dir($production_repository)) {
1780
            $handle = opendir($production_repository);
1781
            while ($file = readdir($handle)) {
1782
                if ($file == '.' ||
1783
                    $file == '..' ||
1784
                    $file == '.htaccess' ||
1785
                    is_dir($production_repository.$file)
1786
                ) {
1787
                    // skip current/parent directory and .htaccess
1788
                    continue;
1789
                }
1790
1791
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
1792
                    // User's photos should not be listed as productions.
1793
                    continue;
1794
                }
1795
                $productions[] = $file;
1796
            }
1797
        }
1798
1799
        return $productions;
1800
    }
1801
1802
    /**
1803
     * Remove a user production.
1804
     *
1805
     * @param   int $user_id        User id
1806
     * @param   string $production    The production to remove
1807
     */
1808
    public static function remove_user_production($user_id, $production)
1809
    {
1810
        $production_path = self::get_user_picture_path_by_id($user_id, 'system');
1811
        $production_file = $production_path['dir'].$production;
1812
        if (is_file($production_file)) {
1813
            unlink($production_file);
1814
            return true;
1815
        }
1816
        return false;
1817
    }
1818
1819
    /**
1820
     * Update an extra field value for a given user
1821
     * @param    integer   $userId User ID
1822
     * @param    string    $variable Field variable name
1823
     * @param    string    $value Field value
1824
     *
1825
     * @return    boolean    true if field updated, false otherwise
1826
     */
1827 View Code Duplication
    public static function update_extra_field_value($userId, $variable, $value = '')
1828
    {
1829
        $extraFieldValue = new ExtraFieldValue('user');
1830
        $params = [
1831
            'item_id' => $userId,
1832
            'variable' => $variable,
1833
            'value' => $value
1834
        ];
1835
        return $extraFieldValue->save($params);
1836
    }
1837
1838
    /**
1839
     * Get an array of extra fields with field details (type, default value and options)
1840
     * @param    integer    Offset (from which row)
1841
     * @param    integer    Number of items
1842
     * @param    integer    Column on which sorting is made
1843
     * @param    string    Sorting direction
1844
     * @param    boolean    Optional. Whether we get all the fields or just the visible ones
1845
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
1846
     * @return    array    Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
1847
     */
1848
    public static function get_extra_fields(
1849
        $from = 0,
1850
        $number_of_items = 0,
1851
        $column = 5,
1852
        $direction = 'ASC',
1853
        $all_visibility = true,
1854
        $field_filter = null
1855
    ) {
1856
        $fields = array();
1857
        $t_uf = Database :: get_main_table(TABLE_EXTRA_FIELD);
1858
        $t_ufo = Database :: get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
1859
        $columns = array(
1860
            'id',
1861
            'variable',
1862
            'field_type',
1863
            'display_text',
1864
            'default_value',
1865
            'field_order',
1866
            'filter'
1867
        );
1868
        $column = intval($column);
1869
        $sort_direction = '';
1870
        if (in_array(strtoupper($direction), array('ASC', 'DESC'))) {
1871
            $sort_direction = strtoupper($direction);
1872
        }
1873
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1874
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
1875
        if (!$all_visibility) {
1876
            $sqlf .= " AND visible = 1 ";
1877
        }
1878
        if (!is_null($field_filter)) {
1879
            $field_filter = intval($field_filter);
1880
            $sqlf .= " AND filter = $field_filter ";
1881
        }
1882
        $sqlf .= " ORDER BY ".$columns[$column]." $sort_direction ";
1883
        if ($number_of_items != 0) {
1884
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
1885
        }
1886
        $resf = Database::query($sqlf);
1887
        if (Database::num_rows($resf) > 0) {
1888
            while ($rowf = Database::fetch_array($resf)) {
1889
                $fields[$rowf['id']] = array(
1890
                    0 => $rowf['id'],
1891
                    1 => $rowf['variable'],
1892
                    2 => $rowf['field_type'],
1893
                    3 => (empty($rowf['display_text']) ? '' : $rowf['display_text']),
1894
                    4 => $rowf['default_value'],
1895
                    5 => $rowf['field_order'],
1896
                    6 => $rowf['visible'],
1897
                    7 => $rowf['changeable'],
1898
                    8 => $rowf['filter'],
1899
                    9 => array(),
1900
                    10 => '<a name="'.$rowf['id'].'"></a>',
1901
                );
1902
1903
                $sqlo = "SELECT * FROM $t_ufo
1904
                         WHERE field_id = ".$rowf['id']."
1905
                         ORDER BY option_order ASC";
1906
                $reso = Database::query($sqlo);
1907
                if (Database::num_rows($reso) > 0) {
1908
                    while ($rowo = Database::fetch_array($reso)) {
1909
                        $fields[$rowf['id']][9][$rowo['id']] = array(
1910
                            0 => $rowo['id'],
1911
                            1 => $rowo['option_value'],
1912
                            2 => (empty($rowo['display_text']) ? '' : $rowo['display_text']),
1913
                            3 => $rowo['option_order']
1914
                        );
1915
                    }
1916
                }
1917
            }
1918
        }
1919
1920
        return $fields;
1921
    }
1922
1923
    /**
1924
     * Build a list of extra file already uploaded in $user_folder/{$extra_field}/
1925
     * @param $user_id
1926
     * @param $extra_field
1927
     * @param bool $force
1928
     * @param bool $showdelete
1929
     * @return bool|string
1930
     */
1931
    public static function build_user_extra_file_list($user_id, $extra_field, $force = false, $showdelete = false)
1932
    {
1933
        if (!$force && !empty($_POST['remove_'.$extra_field])) {
1934
            return true; // postpone reading from the filesystem
1935
        }
1936
1937
        $extra_files = self::get_user_extra_files($user_id, $extra_field);
1938
        if (empty($extra_files)) {
1939
            return false;
1940
        }
1941
1942
        $path_info = self::get_user_picture_path_by_id($user_id, 'web');
1943
        $path = $path_info['dir'];
1944
        $del_image = Display::returnIconPath('delete.png');
1945
1946
        $del_text = get_lang('Delete');
1947
        $extra_file_list = '';
1948
        if (count($extra_files) > 0) {
1949
            $extra_file_list = '<div class="files-production"><ul id="productions">';
1950
            foreach ($extra_files as $file) {
1951
                $filename = substr($file,strlen($extra_field)+1);
1952
                $extra_file_list .= '<li>'.Display::return_icon('archive.png').'<a href="'.$path.$extra_field.'/'.urlencode($filename).'" target="_blank">'.htmlentities($filename).'</a> ';
1953 View Code Duplication
                if ($showdelete) {
1954
                    $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>';
1955
                }
1956
            }
1957
            $extra_file_list .= '</ul></div>';
1958
        }
1959
1960
        return $extra_file_list;
1961
    }
1962
1963
    /**
1964
     * Get valid filenames in $user_folder/{$extra_field}/
1965
     * @param $user_id
1966
     * @param $extra_field
1967
     * @param bool $full_path
1968
     * @return array
1969
     */
1970
    public static function get_user_extra_files($user_id, $extra_field, $full_path = false)
1971
    {
1972
        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...
1973
            // Nothing to do
1974
        } else {
1975
            $path_info = self::get_user_picture_path_by_id($user_id, 'system');
1976
            $path = $path_info['dir'];
1977
        }
1978
        $extra_data = self::get_extra_user_data_by_field($user_id, $extra_field);
1979
        $extra_files = $extra_data[$extra_field];
1980
        if (is_array($extra_files)) {
1981
            foreach ($extra_files as $key => $value) {
1982
                if (!$full_path) {
1983
                    // Relative path from user folder
1984
                    $files[] = $value;
1985
                } else {
1986
                    $files[] = $path.$value;
1987
                }
1988
            }
1989
        } elseif (!empty($extra_files)) {
1990
            if (!$full_path) {
1991
                // Relative path from user folder
1992
                $files[] = $extra_files;
1993
            } else {
1994
                $files[] = $path.$extra_files;
1995
            }
1996
        }
1997
1998
        return $files; // can be an empty array
1999
    }
2000
2001
    /**
2002
     * Remove an {$extra_file} from the user folder $user_folder/{$extra_field}/
2003
     * @param $user_id
2004
     * @param $extra_field
2005
     * @param $extra_file
2006
     * @return bool
2007
     */
2008
    public static function remove_user_extra_file($user_id, $extra_field, $extra_file)
2009
    {
2010
        $extra_file = Security::filter_filename($extra_file);
2011
        $path_info = self::get_user_picture_path_by_id($user_id, 'system');
2012
        if (strpos($extra_file, $extra_field) !== false) {
2013
            $path_extra_file = $path_info['dir'].$extra_file;
2014
        } else {
2015
            $path_extra_file = $path_info['dir'].$extra_field.'/'.$extra_file;
2016
        }
2017
        if (is_file($path_extra_file)) {
2018
            unlink($path_extra_file);
2019
            return true;
2020
        }
2021
        return false;
2022
    }
2023
2024
    /**
2025
     * Creates a new extra field
2026
     * @param    string    $variable Field's internal variable name
2027
     * @param    int       $fieldType  Field's type
2028
     * @param    string    $displayText Field's language var name
2029
     * @param    string    $default Field's default value
2030
     * @return int
2031
     */
2032 View Code Duplication
    public static function create_extra_field($variable, $fieldType, $displayText, $default)
2033
    {
2034
        $extraField = new ExtraField('user');
2035
        $params = [
2036
            'variable' => $variable,
2037
            'field_type' => $fieldType,
2038
            'display_text' => $displayText,
2039
            'default_value' => $default
2040
        ];
2041
2042
        return $extraField->save($params);
2043
    }
2044
2045
    /**
2046
     * Check if a field is available
2047
     * @param    string    th$variable
2048
     * @return    boolean
2049
     */
2050
    public static function is_extra_field_available($variable)
2051
    {
2052
        $extraField = new ExtraField('user');
2053
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2054
        return empty($data) ? true : false;
2055
    }
2056
2057
    /**
2058
     * Gets user extra fields data
2059
     * @param    integer    User ID
2060
     * @param    boolean    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2061
     * @param    boolean    Whether to return invisible fields as well
2062
     * @param    boolean    Whether to split multiple-selection fields or not
2063
     * @return    array    Array of fields => value for the given user
2064
     */
2065
    public static function get_extra_user_data(
2066
        $user_id,
2067
        $prefix = false,
2068
        $all_visibility = true,
2069
        $splitmultiple = false,
2070
        $field_filter = null
2071
    ) {
2072
        // A sanity check.
2073 View Code Duplication
        if (empty($user_id)) {
2074
            $user_id = 0;
2075
        } else {
2076
            if ($user_id != strval(intval($user_id)))
2077
                return array();
2078
        }
2079
        $extra_data = array();
2080
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2081
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2082
        $user_id = intval($user_id);
2083
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2084
                FROM $t_uf f
2085
                WHERE
2086
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2087
                ";
2088
        $filter_cond = '';
2089
2090
        if (!$all_visibility) {
2091
            if (isset($field_filter)) {
2092
                $field_filter = intval($field_filter);
2093
                $filter_cond .= " AND filter = $field_filter ";
2094
            }
2095
            $sql .= " AND f.visible = 1 $filter_cond ";
2096
        } else {
2097
            if (isset($field_filter)) {
2098
                $field_filter = intval($field_filter);
2099
                $sql .= " AND filter = $field_filter ";
2100
            }
2101
        }
2102
2103
        $sql .= " ORDER BY f.field_order";
2104
2105
        $res = Database::query($sql);
2106
        if (Database::num_rows($res) > 0) {
2107
            while ($row = Database::fetch_array($res)) {
2108
                if ($row['type'] == self::USER_FIELD_TYPE_TAG) {
2109
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2110
                    $extra_data['extra_'.$row['fvar']] = $tags;
2111
                } else {
2112
                    $sqlu = "SELECT value as fval
2113
                            FROM $t_ufv
2114
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2115
                    $resu = Database::query($sqlu);
2116
                    // get default value
2117
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2118
                               WHERE id=".$row['id'];
2119
                    $res_df = Database::query($sql_df);
2120
2121
                    if (Database::num_rows($resu) > 0) {
2122
                        $rowu = Database::fetch_array($resu);
2123
                        $fval = $rowu['fval'];
2124
                        if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2125
                            $fval = explode(';', $rowu['fval']);
2126
                        }
2127
                    } else {
2128
                        $row_df = Database::fetch_array($res_df);
2129
                        $fval = $row_df['fval_df'];
2130
                    }
2131
                    // We get here (and fill the $extra_data array) even if there
2132
                    // is no user with data (we fill it with default values)
2133
                    if ($prefix) {
2134 View Code Duplication
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2135
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2136
                        } else {
2137
                            $extra_data['extra_'.$row['fvar']] = $fval;
2138
                        }
2139 View Code Duplication
                    } else {
2140
                        if ($row['type'] == self::USER_FIELD_TYPE_RADIO) {
2141
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2142
                        } else {
2143
                            $extra_data[$row['fvar']] = $fval;
2144
                        }
2145
                    }
2146
                }
2147
            }
2148
        }
2149
2150
        return $extra_data;
2151
    }
2152
2153
    /** Get extra user data by field
2154
     * @param int    user ID
2155
     * @param string the internal variable name of the field
2156
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2157
     */
2158
    public static function get_extra_user_data_by_field(
2159
        $user_id,
2160
        $field_variable,
2161
        $prefix = false,
2162
        $all_visibility = true,
2163
        $splitmultiple = false
2164
    ) {
2165
        // A sanity check.
2166 View Code Duplication
        if (empty($user_id)) {
2167
            $user_id = 0;
2168
        } else {
2169
            if ($user_id != strval(intval($user_id)))
2170
                return array();
2171
        }
2172
        $extra_data = array();
2173
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2174
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2175
        $user_id = intval($user_id);
2176
2177
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2178
                FROM $t_uf f
2179
                WHERE f.variable = '$field_variable' ";
2180
2181
        if (!$all_visibility) {
2182
            $sql .= " AND f.visible = 1 ";
2183
        }
2184
2185
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2186
2187
        $sql .= " ORDER BY f.field_order";
2188
2189
        $res = Database::query($sql);
2190
        if (Database::num_rows($res) > 0) {
2191
            while ($row = Database::fetch_array($res)) {
2192
                $sqlu = "SELECT value as fval FROM $t_ufv v INNER JOIN $t_uf f
2193
                         ON (v.field_id = f.id)
2194
                         WHERE
2195
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2196
                            field_id = ".$row['id']." AND
2197
                            item_id = ".$user_id;
2198
                $resu = Database::query($sqlu);
2199
                $fval = '';
2200
                if (Database::num_rows($resu) > 0) {
2201
                    $rowu = Database::fetch_array($resu);
2202
                    $fval = $rowu['fval'];
2203
                    if ($row['type'] == self::USER_FIELD_TYPE_SELECT_MULTIPLE) {
2204
                        $fval = explode(';', $rowu['fval']);
2205
                    }
2206
                }
2207
                if ($prefix) {
2208
                    $extra_data['extra_'.$row['fvar']] = $fval;
2209
                } else {
2210
                    $extra_data[$row['fvar']] = $fval;
2211
                }
2212
            }
2213
        }
2214
2215
        return $extra_data;
2216
    }
2217
2218
    /**
2219
     * Get the extra field information for a certain field (the options as well)
2220
     * @param  int     $variable The name of the field we want to know everything about
2221
     * @return array   Array containing all the information about the extra profile field
2222
     * (first level of array contains field details, then 'options' sub-array contains options details,
2223
     * as returned by the database)
2224
     * @author Julio Montoya
2225
     * @since v1.8.6
2226
     */
2227
    public static function get_extra_field_information_by_name($variable)
2228
    {
2229
        $extraField = new ExtraField('user');
2230
2231
        return $extraField->get_handler_field_info_by_field_variable($variable);
2232
    }
2233
2234
    /**
2235
     * @param string $type
2236
     *
2237
     * @return array
2238
     */
2239
    public static function get_all_extra_field_by_type($type)
2240
    {
2241
        $extraField = new ExtraField('user');
2242
2243
        return $extraField->get_all_extra_field_by_type($type);
2244
    }
2245
2246
    /**
2247
     * Get all the extra field information of a certain field (also the options)
2248
     *
2249
     * @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...
2250
     * @return array $return containing all th information about the extra profile field
2251
     * @author Julio Montoya
2252
     * @deprecated
2253
     * @since v1.8.6
2254
     */
2255
    public static function get_extra_field_information($fieldId)
2256
    {
2257
        $extraField = new ExtraField('user');
2258
2259
        return $extraField->getFieldInfoByFieldId($fieldId);
2260
    }
2261
2262
    /** Get extra user data by value
2263
     * @param string the internal variable name of the field
2264
     * @param string the internal value of the field
2265
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2266
     */
2267
    public static function get_extra_user_data_by_value($field_variable, $field_value, $all_visibility = true)
2268
    {
2269
        $extraField = new ExtraFieldValue('user');
2270
2271
        $data = $extraField->get_values_by_handler_and_field_variable(
2272
            $field_variable,
2273
            $field_value,
2274
            null,
2275
            true,
2276
            intval($all_visibility)
2277
        );
2278
2279
        $result = [];
2280
        if (!empty($data)) {
2281
            foreach ($data as $data) {
2282
                $result[] = $data['item_id'];
2283
            }
2284
        }
2285
2286
        return $result;
2287
    }
2288
2289
    /**
2290
     * Get extra user data by field variable
2291
     * @param string    field variable
2292
     * @return array    data
2293
     */
2294
    public static function get_extra_user_data_by_field_variable($field_variable)
2295
    {
2296
        $extra_information_by_variable = self::get_extra_field_information_by_name($field_variable);
2297
        $field_id = intval($extra_information_by_variable['id']);
2298
2299
        $extraField = new ExtraFieldValue('user');
2300
        $data = $extraField->getValuesByFieldId($field_id);
2301
2302
        if (!empty($data) > 0) {
2303
            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...
2304
                $user_id = $row['item_id'];
2305
                $data[$user_id] = $row;
2306
            }
2307
        }
2308
2309
        return $data;
2310
    }
2311
2312
    /**
2313
     * Gives a list of [session_category][session_id] for the current user.
2314
     * @param integer $user_id
2315
     * @param boolean whether to fill the first element or not (to give space for courses out of categories)
2316
     * @param boolean  optional true if limit time from session is over, false otherwise
2317
     * @param boolean $ignoreTimeLimit ignore time start/end
2318
     * @return array  list of statuses [session_category][session_id]
2319
     *
2320
     * @todo ensure multiple access urls are managed correctly
2321
     */
2322
    public static function get_sessions_by_category(
2323
        $user_id,
2324
        $is_time_over = true,
2325
        $ignore_visibility_for_admins = false,
2326
        $ignoreTimeLimit = false
2327
    ) {
2328
        // Database Table Definitions
2329
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2330
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2331
        $tbl_session_category = Database :: get_main_table(TABLE_MAIN_SESSION_CATEGORY);
2332
2333
        if ($user_id != strval(intval($user_id))) {
2334
            return array();
2335
        }
2336
2337
        // Get the list of sessions per user
2338
        $now = api_get_utc_datetime();
2339
2340
        $sql = "SELECT DISTINCT
2341
                    session.id,
2342
                    session.name,
2343
                    session.access_start_date,
2344
                    session.access_end_date,
2345
                    session_category_id,
2346
                    session_category.name as session_category_name,
2347
                    session_category.date_start session_category_date_start,
2348
                    session_category.date_end session_category_date_end,
2349
                    coach_access_start_date,
2350
                    coach_access_end_date
2351
              FROM $tbl_session as session
2352
                  LEFT JOIN $tbl_session_category session_category
2353
                  ON (session_category_id = session_category.id)
2354
                  LEFT JOIN $tbl_session_course_user as session_rel_course_user
2355
                  ON (session_rel_course_user.session_id = session.id)
2356
              WHERE (
2357
                    session_rel_course_user.user_id = $user_id OR
2358
                    session.id_coach = $user_id
2359
              )
2360
              ORDER BY session_category_name, name";
2361
2362
        $result = Database::query($sql);
2363
        $categories = array();
2364
        if (Database::num_rows($result) > 0) {
2365
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2366
2367
                // User portal filters:
2368
                if ($ignoreTimeLimit == false) {
2369
                    if ($is_time_over) {
2370
                        // History
2371
                        if (empty($row['access_end_date']) || $row['access_end_date'] == '0000-00-00 00:00:00') {
2372
                            continue;
2373
                        }
2374
2375
                        if (isset($row['access_end_date'])) {
2376
                            if ($row['access_end_date'] > $now) {
2377
                                continue;
2378
                            }
2379
2380
                        }
2381
                    } else {
2382
                        // Current user portal
2383
                        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...
2384
                            // Teachers can access the session depending in the access_coach date
2385
                        } else {
2386
                            if (isset($row['access_end_date']) &&
2387
                                ($row['access_end_date'] != '0000-00-00 00:00:00') &&
2388
                                !empty($row['access_end_date'])
2389
                            ) {
2390
                                if ($row['access_end_date'] <= $now) {
2391
                                    continue;
2392
                                }
2393
                            }
2394
                        }
2395
                    }
2396
                }
2397
2398
                $categories[$row['session_category_id']]['session_category'] = array(
2399
                    'id' => $row['session_category_id'],
2400
                    'name' => $row['session_category_name'],
2401
                    'date_start' => $row['session_category_date_start'],
2402
                    'date_end' => $row['session_category_date_end']
2403
                );
2404
2405
                $session_id = $row['id'];
2406
2407
                $courseList = UserManager::get_courses_list_by_session(
2408
                    $user_id,
2409
                    $row['id']
2410
                );
2411
2412
                // Session visibility.
2413
                $visibility = api_get_session_visibility(
2414
                    $session_id,
2415
                    null,
2416
                    $ignore_visibility_for_admins
2417
                );
2418
2419
2420
                // Course Coach session visibility.
2421
                $blockedCourseCount = 0;
2422
                $closedVisibilityList = array(
2423
                    COURSE_VISIBILITY_CLOSED,
2424
                    COURSE_VISIBILITY_HIDDEN
2425
                );
2426
2427
                foreach ($courseList as $course) {
2428
                    // Checking session visibility
2429
                    $visibility = api_get_session_visibility(
2430
                        $session_id,
2431
                        $course['real_id'],
2432
                        $ignore_visibility_for_admins
2433
                    );
2434
2435
                    $courseIsVisible = !in_array($course['visibility'], $closedVisibilityList);
2436
                    if ($courseIsVisible == false || $visibility == SESSION_INVISIBLE) {
2437
                        $blockedCourseCount++;
2438
                    }
2439
                }
2440
2441
                // If all courses are blocked then no show in the list.
2442
                if ($blockedCourseCount == count($courseList)) {
2443
                    $visibility = SESSION_INVISIBLE;
2444
                }
2445
2446
                switch ($visibility) {
2447
                    case SESSION_VISIBLE_READ_ONLY:
2448
                    case SESSION_VISIBLE:
2449
                    case SESSION_AVAILABLE:
2450
                        break;
2451
                    case SESSION_INVISIBLE:
2452
                        if ($ignore_visibility_for_admins == false) {
2453
                            continue(2);
2454
                        }
2455
                }
2456
2457
                $categories[$row['session_category_id']]['sessions'][$row['id']] = array(
2458
                    'session_name' => $row['name'],
2459
                    'session_id' => $row['id'],
2460
                    'access_start_date' => api_get_local_time($row['access_start_date']),
2461
                    'access_end_date' => api_get_local_time($row['access_end_date']),
2462
                    'coach_access_start_date' => api_get_local_time($row['coach_access_start_date']),
2463
                    'coach_access_end_date' => api_get_local_time($row['coach_access_end_date']),
2464
                    'courses' => $courseList
2465
                );
2466
            }
2467
        }
2468
2469
        return $categories;
2470
    }
2471
2472
    /**
2473
     * Gives a list of [session_id-course_code] => [status] for the current user.
2474
     * @param integer $user_id
2475
     * @return array  list of statuses (session_id-course_code => status)
2476
     */
2477
    public static function get_personal_session_course_list($user_id)
2478
    {
2479
        // Database Table Definitions
2480
        $tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE);
2481
        $tbl_user = Database :: get_main_table(TABLE_MAIN_USER);
2482
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2483
        $tbl_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
2484
        $tbl_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
2485
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2486
2487
        if ($user_id != strval(intval($user_id))) {
2488
            return array();
2489
        }
2490
2491
        // We filter the courses from the URL
2492
        $join_access_url = $where_access_url = '';
2493
2494
        if (api_get_multiple_access_url()) {
2495
            $access_url_id = api_get_current_access_url_id();
2496
            if ($access_url_id != -1) {
2497
                $tbl_url_course = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2498
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2499
                $where_access_url = " AND access_url_id = $access_url_id ";
2500
            }
2501
        }
2502
2503
        // Courses in which we subscribed out of any session
2504
        $tbl_user_course_category = Database :: get_main_table(TABLE_USER_COURSE_CATEGORY);
2505
2506
        $sql = "SELECT
2507
                    course.code,
2508
                    course_rel_user.status course_rel_status,
2509
                    course_rel_user.sort sort,
2510
                    course_rel_user.user_course_cat user_course_cat
2511
                 FROM ".$tbl_course_user." course_rel_user
2512
                 LEFT JOIN ".$tbl_course." course
2513
                 ON course.id = course_rel_user.c_id
2514
                 LEFT JOIN ".$tbl_user_course_category." user_course_category
2515
                 ON course_rel_user.user_course_cat = user_course_category.id
2516
                 $join_access_url
2517
                 WHERE
2518
                    course_rel_user.user_id = '".$user_id."' AND
2519
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2520
                    $where_access_url
2521
                 ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
2522
2523
        $course_list_sql_result = Database::query($sql);
2524
2525
        $personal_course_list = array();
2526
        if (Database::num_rows($course_list_sql_result) > 0) {
2527
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2528
                $course_info = api_get_course_info($result_row['code']);
2529
                $result_row['course_info'] = $course_info;
2530
                $personal_course_list[] = $result_row;
2531
            }
2532
        }
2533
2534
        $coachCourseConditions = null;
2535
2536
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2537
2538 View Code Duplication
        if (api_is_allowed_to_create_course()) {
2539
            $sessionListFromCourseCoach = array();
2540
            $sql =" SELECT DISTINCT session_id
2541
                    FROM $tbl_session_course_user
2542
                    WHERE user_id = $user_id AND status = 2 ";
2543
2544
            $result = Database::query($sql);
2545
            if (Database::num_rows($result)) {
2546
                $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...
2547
                foreach ($result as $session) {
2548
                    $sessionListFromCourseCoach[]= $session['session_id'];
2549
                }
2550
            }
2551
            if (!empty($sessionListFromCourseCoach)) {
2552
                $condition = implode("','", $sessionListFromCourseCoach);
2553
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2554
            }
2555
        }
2556
2557
        // Get the list of sessions where the user is subscribed
2558
        // This is divided into two different queries
2559
        $sessions = array();
2560
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2561
                FROM $tbl_session_user, $tbl_session s
2562
                WHERE (
2563
                    session_id = s.id AND
2564
                    user_id = $user_id AND
2565
                    relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2566
                )
2567
                $coachCourseConditions
2568
                ORDER BY access_start_date, access_end_date, name";
2569
2570
        $result = Database::query($sql);
2571
        if (Database::num_rows($result)>0) {
2572
            while ($row = Database::fetch_assoc($result)) {
2573
                $sessions[$row['id']] = $row;
2574
            }
2575
        }
2576
2577
        $sql = "SELECT DISTINCT
2578
                id, name, access_start_date, access_end_date
2579
                FROM $tbl_session s
2580
                WHERE (
2581
                    id_coach = $user_id
2582
                )
2583
                $coachCourseConditions
2584
                ORDER BY access_start_date, access_end_date, name";
2585
2586
        $result = Database::query($sql);
2587
        if (Database::num_rows($result)>0) {
2588
            while ($row = Database::fetch_assoc($result)) {
2589
                if (empty($sessions[$row['id']])) {
2590
                    $sessions[$row['id']] = $row;
2591
                }
2592
            }
2593
        }
2594
2595
        if (api_is_allowed_to_create_course()) {
2596
            foreach ($sessions as $enreg) {
2597
                $session_id = $enreg['id'];
2598
                $session_visibility = api_get_session_visibility($session_id);
2599
2600
                if ($session_visibility == SESSION_INVISIBLE) {
2601
                    continue;
2602
                }
2603
2604
                // This query is horribly slow when more than a few thousand
2605
                // users and just a few sessions to which they are subscribed
2606
                $id_session = $enreg['id'];
2607
                $personal_course_list_sql = "SELECT DISTINCT
2608
                        course.code code,
2609
                        course.title i,
2610
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
2611
                        email, course.course_language l,
2612
                        1 sort,
2613
                        category_code user_course_cat,
2614
                        access_start_date,
2615
                        access_end_date,
2616
                        session.id as session_id,
2617
                        session.name as session_name
2618
                    FROM $tbl_session_course_user as session_course_user
2619
                        INNER JOIN $tbl_course AS course
2620
                            ON course.id = session_course_user.c_id
2621
                        INNER JOIN $tbl_session as session
2622
                            ON session.id = session_course_user.session_id
2623
                        LEFT JOIN $tbl_user as user
2624
                            ON user.id = session_course_user.user_id OR session.id_coach = user.id
2625
                    WHERE
2626
                        session_course_user.session_id = $id_session AND (
2627
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
2628
                            OR session.id_coach = $user_id
2629
                        )
2630
                    ORDER BY i";
2631
                $course_list_sql_result = Database::query($personal_course_list_sql);
2632
2633 View Code Duplication
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2634
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
2635
                    $key = $result_row['session_id'].' - '.$result_row['code'];
2636
                    $personal_course_list[$key] = $result_row;
2637
                }
2638
            }
2639
        }
2640
2641
        foreach ($sessions as $enreg) {
2642
            $session_id = $enreg['id'];
2643
            $session_visibility = api_get_session_visibility($session_id);
2644
            if ($session_visibility == SESSION_INVISIBLE) {
2645
                continue;
2646
            }
2647
2648
            /* This query is very similar to the above query,
2649
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
2650
            $personal_course_list_sql = "SELECT DISTINCT
2651
                course.code code,
2652
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
2653
                email,
2654
                course.course_language l,
2655
                1 sort,
2656
                category_code user_course_cat,
2657
                access_start_date,
2658
                access_end_date,
2659
                session.id as session_id,
2660
                session.name as session_name,
2661
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
2662
            FROM $tbl_session_course_user as session_course_user
2663
                INNER JOIN $tbl_course AS course
2664
                ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
2665
                INNER JOIN $tbl_session as session ON session_course_user.session_id = session.id
2666
                LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
2667
            WHERE session_course_user.user_id = $user_id
2668
            ORDER BY i";
2669
2670
            $course_list_sql_result = Database::query($personal_course_list_sql);
2671
2672 View Code Duplication
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2673
                $result_row['course_info'] = api_get_course_info($result_row['code']);
2674
                $key = $result_row['session_id'].' - '.$result_row['code'];
2675
                if (!isset($personal_course_list[$key])) {
2676
                    $personal_course_list[$key] = $result_row;
2677
                }
2678
            }
2679
        }
2680
2681
        return $personal_course_list;
2682
    }
2683
2684
    /**
2685
     * Gives a list of courses for the given user in the given session
2686
     * @param integer $user_id
2687
     * @param integer $session_id
2688
     * @return array  list of statuses (session_id-course_code => status)
2689
     */
2690
    public static function get_courses_list_by_session($user_id, $session_id)
2691
    {
2692
        // Database Table Definitions
2693
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2694
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
2695
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2696
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2697
2698
        $user_id = intval($user_id);
2699
        $session_id = intval($session_id);
2700
        //we filter the courses from the URL
2701
        $join_access_url = $where_access_url = '';
2702
2703
        if (api_get_multiple_access_url()) {
2704
            $urlId = api_get_current_access_url_id();
2705
            if ($urlId != -1) {
2706
                $tbl_url_session = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
2707
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
2708
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
2709
            }
2710
        }
2711
2712
        $personal_course_list = array();
2713
        $courses = array();
2714
2715
        /* This query is very similar to the query below, but it will check the
2716
        session_rel_course_user table if there are courses registered
2717
        to our user or not */
2718
2719
        $sql = "SELECT DISTINCT
2720
                    c.visibility,
2721
                    c.id as real_id
2722
                FROM $tbl_session_course_user as scu
2723
                INNER JOIN $tbl_session_course sc
2724
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
2725
                INNER JOIN $tableCourse as c
2726
                ON (scu.c_id = c.id)
2727
                $join_access_url
2728
                WHERE
2729
                    scu.user_id = $user_id AND
2730
                    scu.session_id = $session_id
2731
                    $where_access_url
2732
                ORDER BY sc.position ASC";
2733
2734
        $result = Database::query($sql);
2735
2736 View Code Duplication
        if (Database::num_rows($result) > 0) {
2737
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2738
                $result_row['status'] = 5;
2739
                if (!in_array($result_row['real_id'], $courses)) {
2740
                    $personal_course_list[] = $result_row;
2741
                    $courses[] = $result_row['real_id'];
2742
                }
2743
            }
2744
        }
2745
2746
        if (api_is_allowed_to_create_course()) {
2747
            $sql = "SELECT DISTINCT
2748
                        c.visibility, c.id as real_id
2749
                    FROM $tbl_session_course_user as scu
2750
                    INNER JOIN $tbl_session as s
2751
                    ON (scu.session_id = s.id)
2752
                    INNER JOIN $tbl_session_course sc
2753
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
2754
                    INNER JOIN $tableCourse as c
2755
                    ON (scu.c_id = c.id)
2756
                    $join_access_url
2757
                    WHERE
2758
                      s.id = $session_id AND
2759
                      (
2760
                        (scu.user_id=$user_id AND scu.status=2) OR
2761
                        s.id_coach = $user_id
2762
                      )
2763
                    $where_access_url
2764
                    ORDER BY sc.position ASC";
2765
            $result = Database::query($sql);
2766
2767 View Code Duplication
            if (Database::num_rows($result) > 0) {
2768
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2769
                    $result_row['status'] = 2;
2770
                    if (!in_array($result_row['real_id'], $courses)) {
2771
                        $personal_course_list[] = $result_row;
2772
                        $courses[] = $result_row['real_id'];
2773
                    }
2774
                }
2775
            }
2776
        }
2777
2778
        if (api_is_drh()) {
2779
            $session_list = SessionManager::get_sessions_followed_by_drh($user_id);
2780
            $session_list = array_keys($session_list);
2781
            if (in_array($session_id, $session_list)) {
2782
                $course_list = SessionManager::get_course_list_by_session_id($session_id);
2783
                if (!empty($course_list)) {
2784
                    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...
2785
                        $personal_course_list[] = $course;
2786
                    }
2787
                }
2788
            }
2789
        } else {
2790
            //check if user is general coach for this session
2791
            $s = api_get_session_info($session_id);
2792
            if ($s['id_coach'] == $user_id) {
2793
                $course_list = SessionManager::get_course_list_by_session_id($session_id);
2794
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
                        if (!in_array($course['id'], $courses)) {
2798
                            $personal_course_list[] = $course;
2799
                        }
2800
                    }
2801
                }
2802
            }
2803
        }
2804
2805
        return $personal_course_list;
2806
    }
2807
2808
    /**
2809
     * Get user id from a username
2810
     * @param    string    Username
2811
     * @return    int        User ID (or false if not found)
2812
     */
2813
    public static function get_user_id_from_username($username)
2814
    {
2815
        if (empty($username)) {
2816
            return false;
2817
        }
2818
        $username = trim($username);
2819
        $username = Database::escape_string($username);
2820
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
2821
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
2822
        $res = Database::query($sql);
2823
        if ($res === false) {
2824
            return false;
2825
        }
2826
        if (Database::num_rows($res) !== 1) {
2827
            return false;
2828
        }
2829
        $row = Database::fetch_array($res);
2830
        return $row['id'];
2831
    }
2832
2833
    /**
2834
     * Get the users files upload from his share_folder
2835
     * @param    string    User ID
2836
     * @param   string  course directory
2837
     * @param   string  resourcetype: images, all
2838
     * @return    int        User ID (or false if not found)
2839
     */
2840
    public static function get_user_upload_files_by_course($user_id, $course, $resourcetype = 'all')
2841
    {
2842
        $return = '';
2843
        if (!empty($user_id) && !empty($course)) {
2844
            $user_id = intval($user_id);
2845
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
2846
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
2847
            $file_list = array();
2848
2849
            if (is_dir($path)) {
2850
                $handle = opendir($path);
2851 View Code Duplication
                while ($file = readdir($handle)) {
2852
                    if ($file == '.' || $file == '..' || $file == '.htaccess' || is_dir($path.$file)) {
2853
                        continue; // skip current/parent directory and .htaccess
2854
                    }
2855
                    $file_list[] = $file;
2856
                }
2857
                if (count($file_list) > 0) {
2858
                    $return = "<h4>$course</h4>";
2859
                    $return .= '<ul class="thumbnails">';
2860
                }
2861
                foreach ($file_list as $file) {
2862
                    if ($resourcetype == "all") {
2863
                        $return .= '<li><a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
2864
                    } elseif ($resourcetype == "images") {
2865
                        //get extension
2866
                        $ext = explode('.', $file);
2867
                        if ($ext[1] == 'jpg' || $ext[1] == 'jpeg' || $ext[1] == 'png' || $ext[1] == 'gif' || $ext[1] == 'bmp' || $ext[1] == 'tif') {
2868
                            $return .= '<li class="span2"><a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
2869
                                            <img src="'.$web_path.urlencode($file).'" ></a>
2870
                                        </li>';
2871
                        }
2872
                    }
2873
                }
2874
                if (count($file_list) > 0) {
2875
                    $return .= '</ul>';
2876
                }
2877
            }
2878
        }
2879
        return $return;
2880
    }
2881
2882
    /**
2883
     * Gets the API key (or keys) and return them into an array
2884
     * @param   int     Optional user id (defaults to the result of api_get_user_id())
2885
     * @return  array   Non-indexed array containing the list of API keys for this user, or FALSE on error
2886
     */
2887
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
2888
    {
2889
        if ($user_id != strval(intval($user_id)))
2890
            return false;
2891
        if (empty($user_id)) {
2892
            $user_id = api_get_user_id();
2893
        }
2894
        if ($user_id === false)
2895
            return false;
2896
        $service_name = Database::escape_string($api_service);
2897
        if (is_string($service_name) === false) {
2898
            return false;
2899
        }
2900
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2901
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
2902
        $res = Database::query($sql);
2903
        if ($res === false)
2904
            return false; //error during query
2905
        $num = Database::num_rows($res);
2906
        if ($num == 0)
2907
            return false;
2908
        $list = array();
2909
        while ($row = Database::fetch_array($res)) {
2910
            $list[$row['id']] = $row['api_key'];
2911
        }
2912
        return $list;
2913
    }
2914
2915
    /**
2916
     * Adds a new API key to the users' account
2917
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
2918
     * @return  boolean True on success, false on failure
2919
     */
2920
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
2921
    {
2922
        if ($user_id != strval(intval($user_id)))
2923
            return false;
2924
        if (empty($user_id)) {
2925
            $user_id = api_get_user_id();
2926
        }
2927
        if ($user_id === false)
2928
            return false;
2929
        $service_name = Database::escape_string($api_service);
2930
        if (is_string($service_name) === false) {
2931
            return false;
2932
        }
2933
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2934
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
2935
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
2936
        $res = Database::query($sql);
2937
        if ($res === false)
2938
            return false; //error during query
2939
        $num = Database::insert_id();
2940
        return ($num == 0) ? false : $num;
2941
    }
2942
2943
    /**
2944
     * Deletes an API key from the user's account
2945
     * @param   int     API key's internal ID
2946
     * @return  boolean True on success, false on failure
2947
     */
2948
    public static function delete_api_key($key_id)
2949
    {
2950
        if ($key_id != strval(intval($key_id)))
2951
            return false;
2952
        if ($key_id === false)
2953
            return false;
2954
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2955
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
2956
        $res = Database::query($sql);
2957
        if ($res === false)
2958
            return false; //error during query
2959
        $num = Database::num_rows($res);
2960
        if ($num !== 1)
2961
            return false;
2962
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
2963
        $res = Database::query($sql);
2964
        if ($res === false)
2965
            return false; //error during query
2966
        return true;
2967
    }
2968
2969
    /**
2970
     * Regenerate an API key from the user's account
2971
     * @param   int     user ID (defaults to the results of api_get_user_id())
2972
     * @param   string  API key's internal ID
2973
     * @return  int        num
2974
     */
2975
    public static function update_api_key($user_id, $api_service)
2976
    {
2977
        if ($user_id != strval(intval($user_id)))
2978
            return false;
2979
        if ($user_id === false)
2980
            return false;
2981
        $service_name = Database::escape_string($api_service);
2982
        if (is_string($service_name) === false) {
2983
            return false;
2984
        }
2985
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
2986
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
2987
        $res = Database::query($sql);
2988
        $num = Database::num_rows($res);
2989
        if ($num == 1) {
2990
            $id_key = Database::fetch_array($res, 'ASSOC');
2991
            self::delete_api_key($id_key['id']);
2992
            $num = self::add_api_key($user_id, $api_service);
2993
        } elseif ($num == 0) {
2994
            $num = self::add_api_key($user_id);
2995
        }
2996
        return $num;
2997
    }
2998
2999
    /**
3000
     * @param   int     user ID (defaults to the results of api_get_user_id())
3001
     * @param   string    API key's internal ID
3002
     * @return  int    row ID, or return false if not found
3003
     */
3004
    public static function get_api_key_id($user_id, $api_service)
3005
    {
3006
        if ($user_id != strval(intval($user_id)))
3007
            return false;
3008
        if ($user_id === false)
3009
            return false;
3010
        if (empty($api_service))
3011
            return false;
3012
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3013
        $api_service = Database::escape_string($api_service);
3014
        $sql = "SELECT id FROM $t_api WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3015
        $res = Database::query($sql);
3016
        if (Database::num_rows($res) < 1) {
3017
            return false;
3018
        }
3019
        $row = Database::fetch_array($res, 'ASSOC');
3020
        return $row['id'];
3021
    }
3022
3023
    /**
3024
     * Checks if a user_id is platform admin
3025
     * @param   int user ID
3026
     * @return  boolean True if is admin, false otherwise
3027
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3028
     */
3029
    public static function is_admin($user_id)
3030
    {
3031
        if (empty($user_id) or $user_id != strval(intval($user_id))) {
3032
            return false;
3033
        }
3034
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3035
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3036
        $res = Database::query($sql);
3037
        return Database::num_rows($res) === 1;
3038
    }
3039
3040
    /**
3041
     * Get the total count of users
3042
     * @param   int     Status of users to be counted
3043
     * @param   int     Access URL ID (optional)
3044
     * @return    mixed    Number of users or false on error
3045
     */
3046
    public static function get_number_of_users($status = 0, $access_url_id = null)
3047
    {
3048
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3049
        $t_a = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3050
        $sql = "SELECT count(*) FROM $t_u u";
3051
        $sql2 = '';
3052
        if (is_int($status) && $status > 0) {
3053
            $sql2 .= " WHERE u.status = $status ";
3054
        }
3055
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
3056
            $sql .= ", $t_a a ";
3057
            $sql2 .= " AND a.access_url_id = $access_url_id AND u.id = a.user_id ";
3058
        }
3059
        $sql = $sql.$sql2;
3060
        $res = Database::query($sql);
3061
        if (Database::num_rows($res) === 1) {
3062
            return (int) Database::result($res, 0, 0);
3063
        }
3064
        return false;
3065
    }
3066
3067
    /**
3068
     * @author Isaac flores <[email protected]>
3069
     * @param string The email administrator
3070
     * @param integer The user id
3071
     * @param string The message title
3072
     * @param string The content message
3073
     */
3074
    public static function send_message_in_outbox($email_administrator, $user_id, $title, $content)
3075
    {
3076
        $table_message = Database::get_main_table(TABLE_MESSAGE);
3077
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3078
        $title = api_utf8_decode($title);
3079
        $content = api_utf8_decode($content);
3080
        $email_administrator = Database::escape_string($email_administrator);
3081
        //message in inbox
3082
        $sql_message_outbox = 'SELECT id from '.$table_user.' WHERE email="'.$email_administrator.'" ';
3083
        //$num_row_query = Database::num_rows($sql_message_outbox);
3084
        $res_message_outbox = Database::query($sql_message_outbox);
3085
        $array_users_administrator = array();
3086
        while ($row_message_outbox = Database::fetch_array($res_message_outbox, 'ASSOC')) {
3087
            $array_users_administrator[] = $row_message_outbox['id'];
3088
        }
3089
        //allow to insert messages in outbox
3090
        for ($i = 0; $i < count($array_users_administrator); $i++) {
3091
            $sql_insert_outbox = "INSERT INTO $table_message(user_sender_id, user_receiver_id, msg_status, send_date, title, content ) ".
3092
                " VALUES (".
3093
                "'".(int) $user_id."', '".(int) ($array_users_administrator[$i])."', '4', '".api_get_utc_datetime()."','".Database::escape_string($title)."','".Database::escape_string($content)."'".
3094
                ")";
3095
            Database::query($sql_insert_outbox);
3096
        }
3097
    }
3098
3099
    /*
3100
     *
3101
     * USER TAGS
3102
     *
3103
     * Intructions to create a new user tag by Julio Montoya <[email protected]>
3104
     *
3105
     * 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.
3106
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3107
     * 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
3108
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3109
     * 5. Test and enjoy.
3110
     *
3111
     */
3112
3113
    /**
3114
     * Gets the tags of a specific field_id
3115
     *
3116
     * @param int field_id
3117
     * @param string how we are going to result value in array or in a string (json)
3118
     * @return mixed
3119
     * @since Nov 2009
3120
     * @version 1.8.6.2
3121
     */
3122
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3123
    {
3124
        // database table definition
3125
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3126
        $field_id = intval($field_id);
3127
        $limit = intval($limit);
3128
        $tag = trim(Database::escape_string($tag));
3129
3130
        // all the information of the field
3131
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3132
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3133
        $result = Database::query($sql);
3134
        $return = array();
3135 View Code Duplication
        if (Database::num_rows($result) > 0) {
3136
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3137
                $return[] = array('caption' => $row['tag'], 'value' => $row['tag']);
3138
            }
3139
        }
3140
        if ($return_format == 'json') {
3141
            $return = json_encode($return);
3142
        }
3143
        return $return;
3144
    }
3145
3146
    /**
3147
     * @param int $field_id
3148
     * @param int $limit
3149
     * @return array
3150
     */
3151
    public static function get_top_tags($field_id, $limit = 100)
3152
    {
3153
        // database table definition
3154
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3155
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3156
        $field_id = intval($field_id);
3157
        $limit = intval($limit);
3158
        // all the information of the field
3159
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3160
                INNER JOIN $table_user_tag ut
3161
                ON(ut.id = uv.tag_id)
3162
                WHERE field_id = $field_id
3163
                GROUP BY tag_id
3164
                ORDER BY count DESC
3165
                LIMIT $limit";
3166
        $result = Database::query($sql);
3167
        $return = array();
3168
        if (Database::num_rows($result) > 0) {
3169
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3170
                $return[] = $row;
3171
            }
3172
        }
3173
        return $return;
3174
    }
3175
3176
    /**
3177
     * Get user's tags
3178
     * @param int field_id
3179
     * @param int user_id
3180
     * @return array
3181
     */
3182
    public static function get_user_tags($user_id, $field_id)
3183
    {
3184
        // database table definition
3185
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3186
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3187
        $field_id = intval($field_id);
3188
        $user_id = intval($user_id);
3189
3190
        // all the information of the field
3191
        $sql = "SELECT ut.id, tag, count
3192
                FROM $table_user_tag ut
3193
                INNER JOIN $table_user_tag_values uv
3194
                ON (uv.tag_id=ut.ID)
3195
                WHERE field_id = $field_id AND user_id = $user_id
3196
                ORDER BY tag";
3197
        $result = Database::query($sql);
3198
        $return = array();
3199 View Code Duplication
        if (Database::num_rows($result) > 0) {
3200
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3201
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3202
            }
3203
        }
3204
3205
        return $return;
3206
    }
3207
3208
    /**
3209
     * Get user's tags
3210
     * @param int user_id
3211
     * @param int field_id
3212
     * @param bool show links or not
3213
     * @return array
3214
     */
3215
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3216
    {
3217
        // database table definition
3218
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3219
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3220
        $field_id = intval($field_id);
3221
        $user_id = intval($user_id);
3222
3223
        // all the information of the field
3224
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3225
                INNER JOIN $table_user_tag_values uv
3226
                ON (uv.tag_id = ut.id)
3227
                WHERE field_id = $field_id AND user_id = $user_id
3228
                ORDER BY tag";
3229
3230
        $result = Database::query($sql);
3231
        $return = array();
3232 View Code Duplication
        if (Database::num_rows($result) > 0) {
3233
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3234
                $return[$row['id']] = array('tag' => $row['tag'], 'count' => $row['count']);
3235
            }
3236
        }
3237
        $user_tags = $return;
3238
        $tag_tmp = array();
3239
        foreach ($user_tags as $tag) {
3240
            if ($show_links) {
3241
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.$tag['tag'].'</a>';
3242
            } else {
3243
                $tag_tmp[] = $tag['tag'];
3244
            }
3245
        }
3246
        if (is_array($user_tags) && count($user_tags) > 0) {
3247
            $return = implode(', ', $tag_tmp);
3248
        } else {
3249
            return '';
3250
        }
3251
        return $return;
3252
    }
3253
3254
    /**
3255
     * Get the tag id
3256
     * @param int tag
3257
     * @param int field_id
3258
     * @return int returns 0 if fails otherwise the tag id
3259
     */
3260
    public static function get_tag_id($tag, $field_id)
3261
    {
3262
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3263
        $tag = Database::escape_string($tag);
3264
        $field_id = intval($field_id);
3265
        //with COLLATE latin1_bin to select query in a case sensitive mode
3266
        $sql = "SELECT id FROM $table_user_tag
3267
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3268
        $result = Database::query($sql);
3269
        if (Database::num_rows($result) > 0) {
3270
            $row = Database::fetch_array($result, 'ASSOC');
3271
            return $row['id'];
3272
        } else {
3273
            return 0;
3274
        }
3275
    }
3276
3277
    /**
3278
     * Get the tag id
3279
     * @param int tag
3280
     * @param int field_id
3281
     * @return int 0 if fails otherwise the tag id
3282
     */
3283 View Code Duplication
    public static function get_tag_id_from_id($tag_id, $field_id)
3284
    {
3285
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3286
        $tag_id = intval($tag_id);
3287
        $field_id = intval($field_id);
3288
        $sql = "SELECT id FROM $table_user_tag
3289
                WHERE id = '$tag_id' AND field_id = $field_id";
3290
        $result = Database::query($sql);
3291
        if (Database::num_rows($result) > 0) {
3292
            $row = Database::fetch_array($result, 'ASSOC');
3293
            return $row['id'];
3294
        } else {
3295
            return false;
3296
        }
3297
    }
3298
3299
    /**
3300
     * Adds a user-tag value
3301
     * @param mixed tag
3302
     * @param int The user id
3303
     * @param int field id of the tag
3304
     * @return bool
3305
     */
3306
    public static function add_tag($tag, $user_id, $field_id)
3307
    {
3308
        // database table definition
3309
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3310
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3311
        $tag = trim(Database::escape_string($tag));
3312
        $user_id = intval($user_id);
3313
        $field_id = intval($field_id);
3314
3315
        $tag_id = UserManager::get_tag_id($tag, $field_id);
3316
3317
        /* IMPORTANT
3318
         *  @todo we don't create tags with numbers
3319
         *
3320
         */
3321
        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...
3322
            //the form is sending an id this means that the user select it from the list so it MUST exists
3323
            /* $new_tag_id = UserManager::get_tag_id_from_id($tag,$field_id);
3324
              if ($new_tag_id !== false) {
3325
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3326
              $result = Database::query($sql);
3327
              $last_insert_id = $new_tag_id;
3328
              } else {
3329
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3330
              $result = Database::query($sql);
3331
              $last_insert_id = Database::insert_id();
3332
              } */
3333
        } 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...
3334
3335
        }
3336
3337
        //this is a new tag
3338
        if ($tag_id == 0) {
3339
            //the tag doesn't exist
3340
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3341
             Database::query($sql);
3342
            $last_insert_id = Database::insert_id();
3343
        } else {
3344
            //the tag exists we update it
3345
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3346
             Database::query($sql);
3347
            $last_insert_id = $tag_id;
3348
        }
3349
3350
        if (!empty($last_insert_id) && ($last_insert_id != 0)) {
3351
            //we insert the relationship user-tag
3352
            $sql = "SELECT tag_id FROM $table_user_tag_values
3353
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3354
            $result = Database::query($sql);
3355
            //if the relationship does not exist we create it
3356
            if (Database::num_rows($result) == 0) {
3357
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3358
                Database::query($sql);
3359
            }
3360
        }
3361
    }
3362
3363
    /**
3364
     * Deletes an user tag
3365
     * @param int user id
3366
     * @param int field id
3367
     *
3368
     */
3369
    public static function delete_user_tags($user_id, $field_id)
3370
    {
3371
        // database table definition
3372
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3373
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3374
        $tags = UserManager::get_user_tags($user_id, $field_id);
3375
        if (is_array($tags) && count($tags) > 0) {
3376
            foreach ($tags as $key => $tag) {
3377
                if ($tag['count'] > '0') {
3378
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3379
                    Database::query($sql);
3380
                }
3381
                $sql = "DELETE FROM $table_user_tag_values
3382
                        WHERE user_id = $user_id AND tag_id = $key";
3383
                Database::query($sql);
3384
            }
3385
        }
3386
    }
3387
3388
    /**
3389
     * Process the tag list comes from the UserManager::update_extra_field_value() function
3390
     * @param array the tag list that will be added
3391
     * @param int user id
3392
     * @param int field id
3393
     * @return bool
3394
     */
3395
    public static function process_tags($tags, $user_id, $field_id)
3396
    {
3397
        // We loop the tags and add it to the DB
3398
        if (is_array($tags)) {
3399
            foreach ($tags as $tag) {
3400
                UserManager::add_tag($tag, $user_id, $field_id);
3401
            }
3402
        } else {
3403
            UserManager::add_tag($tags, $user_id, $field_id);
3404
        }
3405
3406
        return true;
3407
    }
3408
3409
    /**
3410
     * Returns a list of all administrators
3411
     * @author jmontoya
3412
     * @return array
3413
     */
3414
    public static function get_all_administrators()
3415
    {
3416
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3417
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3418
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3419
        $access_url_id = api_get_current_access_url_id();
3420
        if (api_get_multiple_access_url()) {
3421
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3422
                    FROM $tbl_url_rel_user as url
3423
                    INNER JOIN $table_admin as admin
3424
                    ON (admin.user_id=url.user_id)
3425
                    INNER JOIN $table_user u
3426
                    ON (u.id=admin.user_id)
3427
                    WHERE access_url_id ='".$access_url_id."'";
3428
        } else {
3429
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3430
                    FROM $table_admin as admin
3431
                    INNER JOIN $table_user u
3432
                    ON (u.id=admin.user_id)";
3433
        }
3434
        $result = Database::query($sql);
3435
        $return = array();
3436
        if (Database::num_rows($result) > 0) {
3437
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3438
                $return[$row['user_id']] = $row;
3439
            }
3440
        }
3441
3442
        return $return;
3443
    }
3444
3445
    /**
3446
     * Search an user (tags, first name, last name and email )
3447
     * @param string $tag
3448
     * @param int $field_id field id of the tag
3449
     * @param int $from where to start in the query
3450
     * @param int $number_of_items
3451
     * @param bool $getCount get count or not
3452
     * @return array
3453
     */
3454
    public static function get_all_user_tags(
3455
        $tag,
3456
        $field_id = 0,
3457
        $from = 0,
3458
        $number_of_items = 10,
3459
        $getCount = false
3460
    ) {
3461
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3462
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3463
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3464
        $access_url_rel_user_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3465
3466
        $field_id = intval($field_id);
3467
        $from = intval($from);
3468
        $number_of_items = intval($number_of_items);
3469
3470
        $where_field = "";
3471
        $where_extra_fields = UserManager::get_search_form_where_extra_fields();
3472
        if ($field_id != 0) {
3473
            $where_field = " field_id = $field_id AND ";
3474
        }
3475
3476
        // all the information of the field
3477
3478
        if ($getCount) {
3479
            $select = "SELECT count(DISTINCT u.id) count";
3480
        } else {
3481
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3482
        }
3483
3484
        $sql = " $select
3485
                FROM $user_table u
3486
                INNER JOIN $access_url_rel_user_table url_rel_user
3487
                ON (u.id = url_rel_user.user_id)
3488
                LEFT JOIN $table_user_tag_values uv
3489
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3490
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3491
                WHERE
3492
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3493
                    (
3494
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3495
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3496
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3497
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3498
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3499
                     )
3500
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3501
                     AND
3502
                     url_rel_user.access_url_id=".api_get_current_access_url_id();
3503
3504
        $keyword_active = true;
3505
        // only active users
3506
        if ($keyword_active) {
3507
            $sql .= " AND u.active='1'";
3508
        }
3509
        // avoid anonymous
3510
        $sql .= " AND u.status <> 6 ";
3511
        $sql .= " ORDER BY username";
3512
        $sql .= " LIMIT $from , $number_of_items";
3513
3514
        $result = Database::query($sql);
3515
        $return = array();
3516
3517
        if (Database::num_rows($result) > 0) {
3518
            if ($getCount) {
3519
                $row = Database::fetch_array($result, 'ASSOC');
3520
                return $row['count'];
3521
            }
3522
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3523
                if (isset($return[$row['id']]) &&
3524
                    !empty($return[$row['id']]['tag'])
3525
                ) {
3526
                    $url = Display::url(
3527
                        $row['tag'],
3528
                        api_get_path(WEB_PATH).'main/social/search.php?q='.$row['tag'],
3529
                        array('class' => 'tag')
3530
                    );
3531
                    $row['tag'] = $url;
3532
                }
3533
                $return[$row['id']] = $row;
3534
            }
3535
        }
3536
3537
        return $return;
3538
    }
3539
3540
    /**
3541
      * Get extra filtrable user fields (only type select)
3542
      * @return array
3543
      */
3544
    public static function get_extra_filtrable_fields()
3545
    {
3546
        $extraFieldList = UserManager::get_extra_fields();
3547
3548
        $extraFiltrableFields = array();
3549 View Code Duplication
        if (is_array($extraFieldList)) {
3550
            foreach ($extraFieldList as $extraField) {
3551
                // If is enabled to filter and is a "<select>" field type
3552
                if ($extraField[8] == 1 && $extraField[2] == 4) {
3553
                    $extraFiltrableFields[] = array(
3554
                        'name' => $extraField[3],
3555
                        'variable' => $extraField[1],
3556
                        'data' => $extraField[9]
3557
                    );
3558
                }
3559
            }
3560
        }
3561
3562
        if (is_array($extraFiltrableFields) && count($extraFiltrableFields) > 0) {
3563
            return $extraFiltrableFields;
3564
        }
3565
    }
3566
3567
    /**
3568
      * Get extra where clauses for finding users based on extra filtrable user fields (type select)
3569
      * @return string With AND clauses based on user's ID which have the values to search in extra user fields
3570
      */
3571
    public static function get_search_form_where_extra_fields()
3572
    {
3573
        $useExtraFields = false;
3574
        $extraFields = UserManager::get_extra_filtrable_fields();
3575
        $extraFieldResult = array();
3576 View Code Duplication
        if (is_array($extraFields) && count($extraFields)>0 ) {
3577
            foreach ($extraFields as $extraField) {
3578
                $varName = 'field_'.$extraField['variable'];
3579
                if (UserManager::is_extra_field_available($extraField['variable'])) {
3580
                    if (isset($_GET[$varName]) && $_GET[$varName]!='0') {
3581
                        $useExtraFields = true;
3582
                        $extraFieldResult[]= UserManager::get_extra_user_data_by_value(
3583
                            $extraField['variable'],
3584
                            $_GET[$varName]
3585
                        );
3586
                    }
3587
                }
3588
            }
3589
        }
3590
3591
        if ($useExtraFields) {
3592
            $finalResult = array();
3593
            if (count($extraFieldResult)>1) {
3594
                for ($i=0; $i < count($extraFieldResult) -1; $i++) {
3595
                    if (is_array($extraFieldResult[$i+1])) {
3596
                        $finalResult  = array_intersect($extraFieldResult[$i], $extraFieldResult[$i+1]);
3597
                    }
3598
                }
3599
            } else {
3600
                $finalResult = $extraFieldResult[0];
3601
            }
3602
3603
            if (is_array($finalResult) && count($finalResult)>0) {
3604
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
3605
            } else {
3606
                //no results
3607
                $whereFilter = " AND u.id  = -1 ";
3608
            }
3609
3610
            return $whereFilter;
3611
        }
3612
    }
3613
3614
    /**
3615
     * Show the search form
3616
     * @param string $query the value of the search box
3617
     * @return string HTML form
3618
     */
3619
    public static function get_search_form($query)
3620
    {
3621
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
3622
        $form = new FormValidator(
3623
            'search_user',
3624
            'get',
3625
            api_get_path(WEB_PATH).'main/social/search.php',
3626
            '',
3627
            array(),
3628
            FormValidator::LAYOUT_HORIZONTAL
3629
        );
3630
3631
        $form->addText('q', get_lang('UsersGroups'), false);
3632
        $options = array(
3633
            0 => get_lang('Select'),
3634
            1 => get_lang('User'),
3635
            2 => get_lang('Group'),
3636
        );
3637
        $form->addSelect(
3638
            'search_type',
3639
            get_lang('Type'),
3640
            $options,
3641
            array('onchange' => 'javascript: extra_field_toogle();')
3642
        );
3643
3644
        // Extra fields
3645
3646
        $extraFields = UserManager::get_extra_filtrable_fields();
3647
        $defaults = [];
3648
        if (is_array($extraFields) && count($extraFields) > 0) {
3649
            foreach ($extraFields as $extraField) {
3650
                $varName = 'field_'.$extraField['variable'];
3651
3652
                $options = [
3653
                    0 => get_lang('Select')
3654
                ];
3655
                foreach ($extraField['data'] as $option) {
3656
                    $checked = '';
3657
                    if (isset($_GET[$varName])) {
3658
                        if ($_GET[$varName] == $option[1]) {
3659
                            $defaults[$option[1]] = true;
3660
                        }
3661
                    }
3662
3663
                    $options[$option[1]] = $option[1];
3664
                }
3665
                $form->addSelect($varName, $extraField['name'], $options);
3666
            }
3667
        }
3668
3669
        $defaults['search_type'] = intval($searchType);
3670
        $defaults['q'] = api_htmlentities(Security::remove_XSS($query));
3671
        $form->setDefaults($defaults);
3672
3673
        $form->addButtonSearch(get_lang('Search'));
3674
3675
        $js = '<script>
3676
        extra_field_toogle();
3677
        function extra_field_toogle() {
3678
            if (jQuery("select[name=search_type]").val() != "1") { jQuery(".extra_field").hide(); } else { jQuery(".extra_field").show(); }
3679
        }
3680
        </script>';
3681
3682
        return $js.$form->returnForm();
3683
    }
3684
3685
    /**
3686
     * Shows the user menu
3687
     */
3688
    public static function show_menu()
3689
    {
3690
        echo '<div class="actions">';
3691
        echo '<a href="/main/auth/profile.php">'.Display::return_icon('profile.png').' '.get_lang('PersonalData').'</a>';
3692
        echo '<a href="/main/messages/inbox.php">'.Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
3693
        echo '<a href="/main/messages/outbox.php">'.Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
3694
        echo '<span style="float:right; padding-top:7px;">'.
3695
        '<a href="/main/auth/profile.php?show=1">'.Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
3696
        '</span>';
3697
        echo '</div>';
3698
    }
3699
3700
    /**
3701
     * Allow to register contact to social network
3702
     * @param int $friend_id user friend id
3703
     * @param int $my_user_id user id
3704
     * @param int $relation_type relation between users see constants definition
3705
     */
3706
    public static function relate_users($friend_id, $my_user_id, $relation_type)
3707
    {
3708
        $tbl_my_friend = Database :: get_main_table(TABLE_MAIN_USER_REL_USER);
3709
3710
        $friend_id = intval($friend_id);
3711
        $my_user_id = intval($my_user_id);
3712
        $relation_type = intval($relation_type);
3713
3714
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
3715
                WHERE
3716
                    friend_user_id='.$friend_id.' AND
3717
                    user_id='.$my_user_id.' AND
3718
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
3719
        $result = Database::query($sql);
3720
        $row = Database :: fetch_array($result, 'ASSOC');
3721
        $current_date = date('Y-m-d H:i:s');
3722
3723
        if ($row['count'] == 0) {
3724
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
3725
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
3726
            Database::query($sql);
3727
            return true;
3728
        } else {
3729
            $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
3730
                    WHERE
3731
                        friend_user_id='.$friend_id.' AND
3732
                        user_id='.$my_user_id.' AND
3733
                        relation_type <> '.USER_RELATION_TYPE_RRHH.' ';
3734
            $result = Database::query($sql);
3735
            $row = Database :: fetch_array($result, 'ASSOC');
3736
            if ($row['count'] == 1) {
3737
                //only for the case of a RRHH
3738
                if ($row['relation_type'] != $relation_type && $relation_type == USER_RELATION_TYPE_RRHH) {
3739
                    $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
3740
                            VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
3741
                } else {
3742
                    $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
3743
                            WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
3744
                }
3745
                Database::query($sql);
3746
3747
                return true;
3748
            } else {
3749
3750
                return false;
3751
            }
3752
        }
3753
    }
3754
3755
    /**
3756
     * Deletes a contact
3757
     * @param int user friend id
3758
     * @param bool true will delete ALL friends relationship from $friend_id
3759
     * @author isaac flores paz <[email protected]>
3760
     * @author Julio Montoya <[email protected]> Cleaning code
3761
     */
3762
    public static function remove_user_rel_user($friend_id, $real_removed = false, $with_status_condition = '')
3763
    {
3764
        $tbl_my_friend = Database :: get_main_table(TABLE_MAIN_USER_REL_USER);
3765
        $tbl_my_message = Database :: get_main_table(TABLE_MESSAGE);
3766
        $friend_id = intval($friend_id);
3767
3768
        if ($real_removed) {
3769
            $extra_condition = '';
3770
            if ($with_status_condition != '') {
3771
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
3772
            }
3773
            $sql = 'DELETE FROM '.$tbl_my_friend.'
3774
                    WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND friend_user_id='.$friend_id.' '.$extra_condition;
3775
            Database::query($sql);
3776
            $sql= 'DELETE FROM '.$tbl_my_friend.'
3777
                   WHERE relation_type <> '.USER_RELATION_TYPE_RRHH.' AND user_id='.$friend_id.' '.$extra_condition;
3778
            Database::query($sql);
3779
        } else {
3780
            $user_id = api_get_user_id();
3781
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
3782
                    WHERE
3783
                        user_id='.$user_id.' AND
3784
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
3785
                        friend_user_id='.$friend_id;
3786
            $result = Database::query($sql);
3787
            $row = Database :: fetch_array($result, 'ASSOC');
3788
            if ($row['count'] == 1) {
3789
                //Delete user rel user
3790
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
3791
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
3792
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
3793
                          WHERE user_receiver_id='.$user_id.' AND user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
3794
                //Delete user
3795
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
3796
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
3797
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
3798
                           WHERE user_receiver_id='.$friend_id.' AND user_sender_id='.$user_id.' AND update_date="0000-00-00 00:00:00" ';
3799
                Database::query($sql_i);
3800
                Database::query($sql_j);
3801
                Database::query($sql_ij);
3802
                Database::query($sql_ji);
3803
            }
3804
        }
3805
    }
3806
3807
    /**
3808
     * @param int $userId
3809
     * @return array
3810
     */
3811
    public static function getDrhListFromUser($userId)
3812
    {
3813
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
3814
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
3815
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3816
        $userId = intval($userId);
3817
3818
        $orderBy = null;
3819
        if (api_is_western_name_order()) {
3820
            $orderBy .= " ORDER BY firstname, lastname ";
3821
        } else {
3822
            $orderBy .= " ORDER BY lastname, firstname ";
3823
        }
3824
3825
        $sql = "SELECT u.id, username, u.firstname, u.lastname
3826
                FROM $tblUser u
3827
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
3828
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
3829
                WHERE
3830
                    access_url_id = ".api_get_current_access_url_id()." AND
3831
                    uru.user_id = '$userId' AND
3832
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
3833
                $orderBy
3834
                ";
3835
        $result = Database::query($sql);
3836
3837
        return Database::store_result($result);
3838
    }
3839
3840
    /**
3841
     * get users followed by human resource manager
3842
     * @param int $userId
3843
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
3844
     * @param bool $getOnlyUserId
3845
     * @param bool $getSql
3846
     * @param bool $getCount
3847
     * @param int $from
3848
     * @param int $numberItems
3849
     * @param int $column
3850
     * @param string $direction
3851
     * @param int $active
3852
     * @param string $lastConnectionDate
3853
     * @return array     users
3854
     */
3855 View Code Duplication
    public static function get_users_followed_by_drh(
3856
        $userId,
3857
        $userStatus = 0,
3858
        $getOnlyUserId = false,
3859
        $getSql = false,
3860
        $getCount = false,
3861
        $from = null,
3862
        $numberItems = null,
3863
        $column = null,
3864
        $direction = null,
3865
        $active = null,
3866
        $lastConnectionDate = null
3867
    ) {
3868
        return self::getUsersFollowedByUser(
3869
            $userId,
3870
            $userStatus,
3871
            $getOnlyUserId,
3872
            $getSql,
3873
            $getCount,
3874
            $from,
3875
            $numberItems,
3876
            $column,
3877
            $direction,
3878
            $active,
3879
            $lastConnectionDate,
3880
            DRH
3881
        );
3882
    }
3883
3884
    /**
3885
    * Get users followed by human resource manager
3886
    * @param int $userId
3887
    * @param int  $userStatus Filter users by status (STUDENT, COURSEMANAGER, etc)
3888
    * @param bool $getOnlyUserId
3889
    * @param bool $getSql
3890
    * @param bool $getCount
3891
    * @param int $from
3892
    * @param int $numberItems
3893
    * @param int $column
3894
    * @param string $direction
3895
    * @param int $active
3896
    * @param string $lastConnectionDate
3897
    * @param int $status the function is called by who? COURSEMANAGER, DRH?
3898
    * @param string $keyword
3899
     *
3900
    * @return array user list
3901
    */
3902
    public static function getUsersFollowedByUser(
3903
        $userId,
3904
        $userStatus = null,
3905
        $getOnlyUserId = false,
3906
        $getSql = false,
3907
        $getCount = false,
3908
        $from = null,
3909
        $numberItems = null,
3910
        $column = null,
3911
        $direction = null,
3912
        $active = null,
3913
        $lastConnectionDate = null,
3914
        $status = null,
3915
        $keyword = null
3916
    ) {
3917
        // Database Table Definitions
3918
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
3919
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
3920
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3921
3922
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3923
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3924
3925
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3926
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3927
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3928
3929
        $userId = intval($userId);
3930
3931
        $limitCondition = null;
3932
3933 View Code Duplication
        if (isset($from) && isset($numberItems)) {
3934
            $from = intval($from);
3935
            $numberItems = intval($numberItems);
3936
            $limitCondition = "LIMIT $from, $numberItems";
3937
        }
3938
3939
        $column = Database::escape_string($column);
3940
        $direction = in_array(strtolower($direction), array('asc', 'desc')) ? $direction : null;
3941
3942
        $userConditions = '';
3943
        if (!empty($userStatus)) {
3944
            $userConditions .= ' AND u.status = '.intval($userStatus);
3945
        }
3946
3947
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
3948
        if ($getOnlyUserId) {
3949
            $select = " SELECT DISTINCT u.id user_id";
3950
        }
3951
3952
        $masterSelect = "SELECT DISTINCT * FROM ";
3953
3954
        if ($getCount) {
3955
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
3956
            $select = " SELECT DISTINCT(u.id) user_id";
3957
        }
3958
3959
        if (!is_null($active)) {
3960
            $active = intval($active);
3961
            $userConditions .= " AND u.active = $active ";
3962
        }
3963
3964 View Code Duplication
        if (!empty($keyword)) {
3965
            $keyword = Database::escape_string($keyword);
3966
            $userConditions .= " AND (
3967
                u.username LIKE '%$keyword%' OR
3968
                u.firstname LIKE '%$keyword%' OR
3969
                u.lastname LIKE '%$keyword%' OR
3970
                u.official_code LIKE '%$keyword%' OR
3971
                u.email LIKE '%$keyword%'
3972
            )";
3973
        }
3974
3975
        if (!empty($lastConnectionDate)) {
3976
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
3977
            $userConditions .=  " AND u.last_login <= '$lastConnectionDate' ";
3978
        }
3979
3980
        $courseConditions = null;
3981
        $sessionConditionsCoach = null;
3982
        $sessionConditionsTeacher = null;
3983
        $drhConditions = null;
3984
        $teacherSelect = null;
3985
3986
        switch ($status) {
3987
            case DRH:
3988
                $drhConditions .= " AND
3989
                    friend_user_id = '$userId' AND
3990
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
3991
                ";
3992
                break;
3993
            case COURSEMANAGER:
3994
                $drhConditions .= " AND
3995
                    friend_user_id = '$userId' AND
3996
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
3997
                ";
3998
3999
                $sessionConditionsCoach .= " AND
4000
                    (s.id_coach = '$userId')
4001
                ";
4002
4003
                $sessionConditionsTeacher .= " AND
4004
                    (scu.status = 2 AND scu.user_id = '$userId')
4005
                ";
4006
4007
                $teacherSelect =
4008
                "UNION ALL (
4009
                        $select
4010
                        FROM $tbl_user u
4011
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4012
                        WHERE
4013
                            sru.session_id IN (
4014
                                SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4015
                                $tbl_session_rel_access_url
4016
                                WHERE access_url_id = ".api_get_current_access_url_id()."
4017
                                $sessionConditionsCoach
4018
                                UNION (
4019
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4020
                                    INNER JOIN $tbl_session_rel_access_url url
4021
                                    ON (url.session_id = s.id)
4022
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4023
                                    ON (scu.session_id = s.id)
4024
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4025
                                    $sessionConditionsTeacher
4026
                                )
4027
                            )
4028
                            $userConditions
4029
                    )
4030
                    UNION ALL(
4031
                        $select
4032
                        FROM $tbl_user u
4033
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4034
                        WHERE cu.c_id IN (
4035
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4036
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4037
                        )
4038
                        $userConditions
4039
                    )"
4040
                ;
4041
                break;
4042
            case STUDENT_BOSS :
4043
                $drhConditions = " AND friend_user_id = $userId AND "
4044
                . "relation_type = " . USER_RELATION_TYPE_BOSS;
4045
                break;
4046
        }
4047
4048
        $join = null;
4049
        $sql = " $masterSelect
4050
                (
4051
                    (
4052
                        $select
4053
                        FROM $tbl_user u
4054
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4055
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4056
                        $join
4057
                        WHERE
4058
                            access_url_id = ".api_get_current_access_url_id()."
4059
                            $drhConditions
4060
                            $userConditions
4061
                    )
4062
                    $teacherSelect
4063
4064
                ) as t1";
4065
4066
        if ($getSql) {
4067
            return $sql;
4068
        }
4069
        if ($getCount) {
4070
            $result = Database::query($sql);
4071
            $row = Database::fetch_array($result);
4072
            return $row['count'];
4073
        }
4074
4075
        $orderBy = null;
4076
        if (api_is_western_name_order()) {
4077
            $orderBy .= " ORDER BY firstname, lastname ";
4078
        } else {
4079
            $orderBy .= " ORDER BY lastname, firstname ";
4080
        }
4081
4082 View Code Duplication
        if (!empty($column) && !empty($direction)) {
4083
            // Fixing order due the UNIONs
4084
            $column = str_replace('u.', '', $column);
4085
            $orderBy = " ORDER BY $column $direction ";
4086
        }
4087
4088
        $sql .= $orderBy;
4089
        $sql .= $limitCondition;
4090
        $result = Database::query($sql);
4091
        $users = array();
4092
        if (Database::num_rows($result) > 0) {
4093
4094
            while ($row = Database::fetch_array($result)) {
4095
                $users[$row['user_id']] = $row;
4096
            }
4097
        }
4098
4099
        return $users;
4100
    }
4101
4102
    /**
4103
     * Subscribes users to human resource manager (Dashboard feature)
4104
     *    @param    int         hr dept id
4105
     * @param    array        Users id
4106
     * @param    int            affected rows
4107
     * */
4108
    public static function suscribe_users_to_hr_manager($hr_dept_id, $users_id)
4109
    {
4110
        return self::subscribeUsersToUser($hr_dept_id, $users_id, USER_RELATION_TYPE_RRHH);
4111
    }
4112
4113
    /**
4114
     * Add subscribed users to a user by relation type
4115
     * @param int $userId The user id
4116
     * @param array $subscribedUsersId The id of suscribed users
4117
     * @param action $relationType The relation type
4118
     */
4119
    public static function subscribeUsersToUser($userId, $subscribedUsersId, $relationType)
4120
    {
4121
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4122
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4123
4124
        $userId = intval($userId);
4125
        $relationType = intval($relationType);
4126
        $affectedRows = 0;
4127
4128
        if (api_get_multiple_access_url()) {
4129
            //Deleting assigned users to hrm_id
4130
            $sql = "SELECT s.user_id FROM $userRelUserTable s "
4131
                . "INNER JOIN $userRelAccessUrlTable a ON (a.user_id = s.user_id) "
4132
                . "WHERE friend_user_id = $userId "
4133
                . "AND relation_type = $relationType "
4134
                . "AND access_url_id = " . api_get_current_access_url_id() . "";
4135
        } else {
4136
            $sql = "SELECT user_id FROM $userRelUserTable "
4137
                . "WHERE friend_user_id = $userId "
4138
                . "AND relation_type = $relationType";
4139
        }
4140
        $result = Database::query($sql);
4141
4142 View Code Duplication
        if (Database::num_rows($result) > 0) {
4143
            while ($row = Database::fetch_array($result)) {
4144
                $sql = "DELETE FROM $userRelUserTable "
4145
                    . "WHERE user_id = {$row['user_id']} "
4146
                    . "AND friend_user_id = $userId "
4147
                    . "AND relation_type = $relationType";
4148
4149
                Database::query($sql);
4150
            }
4151
        }
4152
4153
        // Inserting new user list
4154
        if (is_array($subscribedUsersId)) {
4155
            foreach ($subscribedUsersId as $subscribedUserId) {
4156
                $subscribedUserId = intval($subscribedUserId);
4157
4158
                $sql = "INSERT IGNORE INTO $userRelUserTable(user_id, friend_user_id, relation_type) "
4159
                    . "VALUES ($subscribedUserId, $userId, $relationType)";
4160
4161
                $result = Database::query($sql);
4162
4163
                $affectedRows = Database::affected_rows($result);
4164
            }
4165
        }
4166
4167
        return $affectedRows;
4168
    }
4169
4170
    /**
4171
     * This function check if an user is followed by human resources manager
4172
     * @param     int     User id
4173
     * @param    int        Human resources manager
4174
     * @return    bool
4175
     */
4176
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4177
    {
4178
        // Database table and variables Definitions
4179
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4180
        $user_id = intval($user_id);
4181
        $hr_dept_id = intval($hr_dept_id);
4182
        $result = false;
4183
4184
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4185
                WHERE
4186
                    user_id = $user_id AND
4187
                    friend_user_id = $hr_dept_id AND
4188
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4189
        $rs = Database::query($sql);
4190
        if (Database::num_rows($rs) > 0) {
4191
            $result = true;
4192
        }
4193
        return $result;
4194
    }
4195
4196
    /**
4197
     * get user id of teacher or session administrator
4198
     * @param array $courseInfo
4199
     *
4200
     * @return int The user id
4201
     */
4202
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4203
    {
4204
        $session = api_get_session_id();
4205
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4206
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4207
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4208
        $courseId = $courseInfo['real_id'];
4209
        $courseCode = $courseInfo['code'];
4210
4211
        if ($session == 0 || is_null($session)) {
4212
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4213
                    INNER JOIN '.$table_course_user.' ru
4214
                    ON ru.user_id = u.id
4215
                    WHERE
4216
                        ru.status = 1 AND
4217
                        ru.c_id = "'.$courseId.'" ';
4218
            $rs = Database::query($sql);
4219
            $num_rows = Database::num_rows($rs);
4220
            if ($num_rows == 1) {
4221
                $row = Database::fetch_array($rs);
4222
                return $row['uid'];
4223
            } else {
4224
                $my_num_rows = $num_rows;
4225
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4226
                return $my_user_id;
4227
            }
4228
        } elseif ($session > 0) {
4229
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4230
                    INNER JOIN '.$table_session_course_user.' sru
4231
                    ON sru.user_id=u.id
4232
                    WHERE
4233
                        sru.c_id="'.$courseId.'" AND
4234
                        sru.status=2';
4235
            $rs = Database::query($sql);
4236
            $row = Database::fetch_array($rs);
4237
4238
            return $row['uid'];
4239
        }
4240
    }
4241
4242
    /**
4243
     * Determines if a user is a gradebook certified
4244
     * @param int The category id of gradebook
4245
     * @param int The user id
4246
     * @return boolean
4247
     */
4248
    public static function is_user_certified($cat_id, $user_id)
4249
    {
4250
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4251
        $sql = 'SELECT path_certificate FROM '.$table_certificate.'
4252
                WHERE
4253
                    cat_id="'.intval($cat_id).'" AND
4254
                    user_id="'.intval($user_id).'"';
4255
        $rs = Database::query($sql);
4256
        $row = Database::fetch_array($rs);
4257
        if ($row['path_certificate'] == '' || is_null($row['path_certificate'])) {
4258
            return false;
4259
        } else {
4260
            return true;
4261
        }
4262
    }
4263
4264
    /**
4265
     * Gets the info about a gradebook certificate for a user by course
4266
     * @param string The course code
4267
     * @param int The user id
4268
     * @return array  if there is not information return false
4269
     */
4270
    public static function get_info_gradebook_certificate($course_code, $user_id)
4271
    {
4272
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4273
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4274
        $session_id = api_get_session_id();
4275
4276
        if (empty($session_id)) {
4277
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4278
        } else {
4279
            $session_condition = " AND session_id = $session_id";
4280
        }
4281
4282
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.' WHERE cat_id = (SELECT id FROM '.$tbl_grade_category.'
4283
                WHERE
4284
                    course_code = "'.Database::escape_string($course_code).'" '.$session_condition.' LIMIT 1 ) AND
4285
                    user_id='.intval($user_id);
4286
4287
        $rs = Database::query($sql);
4288
        if (Database::num_rows($rs) > 0) {
4289
            $row = Database::fetch_array($rs, 'ASSOC');
4290
            $score = $row['score_certificate'];
4291
            $category_id = $row['cat_id'];
4292
            $cat = Category::load($category_id);
4293
            $displayscore = ScoreDisplay::instance();
4294
            if (isset($cat) && $displayscore->is_custom()) {
4295
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()), SCORE_DIV_PERCENT_WITH_CUSTOM);
4296
            } else {
4297
                $grade = $displayscore->display_score(array($score, $cat[0]->get_weight()));
4298
            }
4299
            $row['grade'] = $grade;
4300
            return $row;
4301
        }
4302
        return false;
4303
    }
4304
4305
    /**
4306
     * Gets the user path of user certificated
4307
     * @param int The user id
4308
     * @return array  containing path_certificate and cat_id
4309
     */
4310
    public static function get_user_path_certificate($user_id)
4311
    {
4312
        $my_certificate = array();
4313
        $table_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4314
        $table_gradebook_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4315
4316
        $session_id = api_get_session_id();
4317
        $user_id = intval($user_id);
4318 View Code Duplication
        if ($session_id == 0 || is_null($session_id)) {
4319
            $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
4320
        } elseif ($session_id > 0) {
4321
            $sql_session = 'AND session_id='.intval($session_id);
4322
        } else {
4323
            $sql_session = '';
4324
        }
4325
        $sql = "SELECT tc.path_certificate,tc.cat_id,tgc.course_code,tgc.name
4326
                FROM $table_certificate tc, $table_gradebook_category tgc
4327
                WHERE tgc.id = tc.cat_id AND tc.user_id = $user_id
4328
                ORDER BY tc.date_certificate DESC limit 5";
4329
4330
        $rs = Database::query($sql);
4331
        while ($row = Database::fetch_array($rs)) {
4332
            $my_certificate[] = $row;
4333
        }
4334
        return $my_certificate;
4335
    }
4336
4337
    /**
4338
     * This function check if the user is a coach inside session course
4339
     * @param  int     User id
4340
     * @param  int  $courseId
4341
     * @param  int     Session id
4342
     * @return bool    True if the user is a coach
4343
     *
4344
     */
4345
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4346
    {
4347
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4348
        // Protect data
4349
        $user_id = intval($user_id);
4350
        $courseId = intval($courseId);
4351
        $session_id = intval($session_id);
4352
        $result = false;
4353
4354
        $sql = "SELECT session_id FROM $tbl_session_course_rel_user
4355
                WHERE
4356
                  session_id = $session_id AND
4357
                  c_id = $courseId AND
4358
                  user_id = $user_id AND
4359
                  status = 2 ";
4360
        $res = Database::query($sql);
4361
4362
        if (Database::num_rows($res) > 0) {
4363
            $result = true;
4364
        }
4365
        return $result;
4366
    }
4367
4368
    /**
4369
     * This function returns an icon path that represents the favicon of the website of which the url given.
4370
     * Defaults to the current Chamilo favicon
4371
     * @param    string    URL of website where to look for favicon.ico
4372
     * @param    string    Optional second URL of website where to look for favicon.ico
4373
     * @return    string    Path of icon to load
4374
     */
4375
    public static function get_favicon_from_url($url1, $url2 = null)
4376
    {
4377
        $icon_link = '';
4378
        $url = $url1;
4379
        if (empty($url1)) {
4380
            $url = $url2;
4381
            if (empty($url)) {
4382
                $url = api_get_access_url(api_get_current_access_url_id());
4383
                $url = $url[0];
4384
            }
4385
        }
4386
        if (!empty($url)) {
4387
            $pieces = parse_url($url);
4388
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
4389
        }
4390
        return $icon_link;
4391
    }
4392
4393
    /**
4394
     *
4395
     * @param int   student id
4396
     * @param int   years
4397
     * @param bool  show warning_message
4398
     * @param bool  return_timestamp
4399
     */
4400
    public static function delete_inactive_student($student_id, $years = 2, $warning_message = false, $return_timestamp = false)
4401
    {
4402
        $tbl_track_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
4403
        $sql = 'SELECT login_date FROM '.$tbl_track_login.'
4404
                WHERE login_user_id = '.intval($student_id).'
4405
                ORDER BY login_date DESC LIMIT 0,1';
4406
        if (empty($years)) {
4407
            $years = 1;
4408
        }
4409
        $inactive_time = $years * 31536000;  //1 year
4410
        $rs = Database::query($sql);
4411
        if (Database::num_rows($rs) > 0) {
4412
            if ($last_login_date = Database::result($rs, 0, 0)) {
4413
                $last_login_date = api_get_local_time($last_login_date, null, date_default_timezone_get());
4414
                if ($return_timestamp) {
4415
                    return api_strtotime($last_login_date);
4416
                } else {
4417
                    if (!$warning_message) {
4418
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
4419
                    } else {
4420
                        $timestamp = api_strtotime($last_login_date);
4421
                        $currentTimestamp = time();
4422
4423
                        //If the last connection is > than 7 days, the text is red
4424
                        //345600 = 7 days in seconds 63072000= 2 ans
4425
                        // if ($currentTimestamp - $timestamp > 184590 )
4426
                        if ($currentTimestamp - $timestamp > $inactive_time && UserManager::delete_user($student_id)) {
4427
                            Display :: display_normal_message(get_lang('UserDeleted'));
4428
                            echo '<p>', 'id', $student_id, ':', $last_login_date, '</p>';
4429
                        }
4430
                    }
4431
                }
4432
            }
4433
        }
4434
        return false;
4435
    }
4436
4437
    /**
4438
     * @param FormValidator $form
4439
     * @param $extra_data
4440
     * @param $form_name
4441
     * @param bool $admin_permissions
4442
     * @param null $user_id
4443
     * @deprecated
4444
     * @return array
4445
     */
4446
    static function set_extra_fields_in_form(
4447
        $form,
4448
        $extra_data,
4449
        $admin_permissions = false,
4450
        $user_id = null
4451
    ) {
4452
        $user_id = intval($user_id);
4453
4454
        // EXTRA FIELDS
4455
        $extra = UserManager::get_extra_fields(0, 50, 5, 'ASC');
4456
        $jquery_ready_content = null;
4457
        foreach ($extra as $field_details) {
4458
4459
            if (!$admin_permissions) {
4460
                if ($field_details[6] == 0) {
4461
                    continue;
4462
                }
4463
            }
4464
4465
            switch ($field_details[2]) {
4466 View Code Duplication
                case ExtraField::FIELD_TYPE_TEXT:
4467
                    $form->addElement('text', 'extra_'.$field_details[1], $field_details[3], array('size' => 40));
4468
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4469
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4470
                    $form->applyFilter('extra_'.$field_details[1], 'html_filter');
4471
4472
                    if (!$admin_permissions) {
4473
                        if ($field_details[7] == 0) {
4474
                            $form->freeze('extra_'.$field_details[1]);
4475
                        }
4476
                    }
4477
                    break;
4478 View Code Duplication
                case ExtraField::FIELD_TYPE_TEXTAREA:
4479
                    $form->addHtmlEditor(
4480
                        'extra_'.$field_details[1],
4481
                        $field_details[3],
4482
                        false,
4483
                        false,
4484
                        array('ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130')
4485
                    );
4486
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4487
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4488
                    if (!$admin_permissions) {
4489
                        if ($field_details[7] == 0)
4490
                            $form->freeze('extra_'.$field_details[1]);
4491
                    }
4492
                    break;
4493
                case ExtraField::FIELD_TYPE_RADIO:
4494
                    $group = array();
4495 View Code Duplication
                    foreach ($field_details[9] as $option_id => $option_details) {
4496
                        $options[$option_details[1]] = $option_details[2];
4497
                        $group[] = $form->createElement(
4498
                            'radio',
4499
                            'extra_'.$field_details[1],
4500
                            $option_details[1],
4501
                            $option_details[2].'<br />',
4502
                            $option_details[1]
4503
                        );
4504
                    }
4505
                    $form->addGroup($group, 'extra_'.$field_details[1], $field_details[3], '');
4506
                    if (!$admin_permissions) {
4507
                        if ($field_details[7] == 0)
4508
                            $form->freeze('extra_'.$field_details[1]);
4509
                    }
4510
                    break;
4511
                case ExtraField::FIELD_TYPE_SELECT:
4512
                    $get_lang_variables = false;
4513 View Code Duplication
                    if (in_array(
4514
                        $field_details[1],
4515
                        array(
4516
                            'mail_notify_message',
4517
                            'mail_notify_invitation',
4518
                            'mail_notify_group_message',
4519
                        )
4520
                    )) {
4521
                        $get_lang_variables = true;
4522
                    }
4523
                    $options = array();
4524
4525
                    foreach ($field_details[9] as $option_id => $option_details) {
4526
                        if ($get_lang_variables) {
4527
                            $options[$option_details[1]] = get_lang($option_details[2]);
4528
                        } else {
4529
                            $options[$option_details[1]] = $option_details[2];
4530
                        }
4531
                    }
4532
4533
                    if ($get_lang_variables) {
4534
                        $field_details[3] = get_lang($field_details[3]);
4535
                    }
4536
4537
                    $form->addElement(
4538
                        'select',
4539
                        'extra_'.$field_details[1],
4540
                        $field_details[3],
4541
                        $options,
4542
                        array('id' => 'extra_' . $field_details[1])
4543
                    );
4544
4545
                    if (!$admin_permissions) {
4546
                        if ($field_details[7] == 0)
4547
                            $form->freeze('extra_'.$field_details[1]);
4548
                    }
4549
                    break;
4550 View Code Duplication
                case ExtraField::FIELD_TYPE_SELECT_MULTIPLE:
4551
                    $options = array();
4552
                    foreach ($field_details[9] as $option_id => $option_details) {
4553
                        $options[$option_details[1]] = $option_details[2];
4554
                    }
4555
                    $form->addElement(
4556
                        'select',
4557
                        'extra_'.$field_details[1],
4558
                        $field_details[3],
4559
                        $options,
4560
                        array('multiple' => 'multiple')
4561
                    );
4562
                    if (!$admin_permissions) {
4563
                        if ($field_details[7] == 0)
4564
                            $form->freeze('extra_'.$field_details[1]);
4565
                    }
4566
                    break;
4567 View Code Duplication
                case ExtraField::FIELD_TYPE_DATE:
4568
                    $form->addDatePicker('extra_'.$field_details[1], $field_details[3]);
4569
                    $defaults['extra_'.$field_details[1]] = date('Y-m-d 12:00:00');
4570
                    $form->setDefaults($defaults);
4571
                    if (!$admin_permissions) {
4572
                        if ($field_details[7] == 0)
4573
                            $form->freeze('extra_'.$field_details[1]);
4574
                    }
4575
                    $form->applyFilter('theme', 'trim');
4576
                    break;
4577 View Code Duplication
                case ExtraField::FIELD_TYPE_DATETIME:
4578
                    $form->addDateTimePicker('extra_'.$field_details[1], $field_details[3]);
4579
                    $defaults['extra_'.$field_details[1]] = date('Y-m-d 12:00:00');
4580
                    $form->setDefaults($defaults);
4581
                    if (!$admin_permissions) {
4582
                        if ($field_details[7] == 0)
4583
                            $form->freeze('extra_'.$field_details[1]);
4584
                    }
4585
                    $form->applyFilter('theme', 'trim');
4586
                    break;
4587
                case ExtraField::FIELD_TYPE_DOUBLE_SELECT:
4588
                    foreach ($field_details[9] as $key => $element) {
4589
                        if ($element[2][0] == '*') {
4590
                            $values['*'][$element[0]] = str_replace('*', '', $element[2]);
4591
                        } else {
4592
                            $values[0][$element[0]] = $element[2];
4593
                        }
4594
                    }
4595
4596
                    $group = '';
4597
                    $group[] = $form->createElement('select', 'extra_'.$field_details[1], '', $values[0], '');
4598
                    $group[] = $form->createElement('select', 'extra_'.$field_details[1].'*', '', $values['*'], '');
4599
                    $form->addGroup($group, 'extra_'.$field_details[1], $field_details[3], '&nbsp;');
4600
4601
                    if (!$admin_permissions) {
4602
                        if ($field_details[7] == 0)
4603
                            $form->freeze('extra_'.$field_details[1]);
4604
                    }
4605
4606
                    /* Recoding the selected values for double : if the user has
4607
                    selected certain values, we have to assign them to the
4608
                    correct select form */
4609
                    if (array_key_exists('extra_'.$field_details[1], $extra_data)) {
4610
                        // exploding all the selected values (of both select forms)
4611
                        $selected_values = explode(';', $extra_data['extra_'.$field_details[1]]);
4612
                        $extra_data['extra_'.$field_details[1]] = array();
4613
4614
                        // looping through the selected values and assigning the selected values to either the first or second select form
4615
                        foreach ($selected_values as $key => $selected_value) {
4616
                            if (array_key_exists($selected_value, $values[0])) {
4617
                                $extra_data['extra_'.$field_details[1]]['extra_'.$field_details[1]] = $selected_value;
4618
                            } else {
4619
                                $extra_data['extra_'.$field_details[1]]['extra_'.$field_details[1].'*'] = $selected_value;
4620
                            }
4621
                        }
4622
                    }
4623
                    break;
4624
                case ExtraField::FIELD_TYPE_DIVIDER:
4625
                    $form->addElement('static', $field_details[1], '<br /><strong>'.$field_details[3].'</strong>');
4626
                    break;
4627
                case ExtraField::FIELD_TYPE_TAG:
4628
                    //the magic should be here
4629
                    $user_tags = UserManager::get_user_tags($user_id, $field_details[0]);
4630
4631
                    $tag_list = '';
4632
                    if (is_array($user_tags) && count($user_tags) > 0) {
4633
                        foreach ($user_tags as $tag) {
4634
                            $tag_list .= '<option value="'.$tag['tag'].'" class="selected">'.$tag['tag'].'</option>';
4635
                        }
4636
                    }
4637
4638
                    $multi_select = '<select id="extra_'.$field_details[1].'" name="extra_'.$field_details[1].'">
4639
                                    '.$tag_list.'
4640
                                    </select>';
4641
4642
                    $form->addElement('label', $field_details[3], $multi_select);
4643
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php';
4644
                    $complete_text = get_lang('StartToType');
4645
                    //if cache is set to true the jquery will be called 1 time
4646
                    $jquery_ready_content = <<<EOF
4647
                    $("#extra_$field_details[1]").fcbkcomplete({
4648
                        json_url: "$url?a=search_tags&field_id=$field_details[0]",
4649
                        cache: false,
4650
                        filter_case: true,
4651
                        filter_hide: true,
4652
                        complete_text:"$complete_text",
4653
                        firstselected: true,
4654
                        //onremove: "testme",
4655
                        //onselect: "testme",
4656
                        filter_selected: true,
4657
                        newel: true
4658
                    });
4659
EOF;
4660
                    break;
4661 View Code Duplication
                case ExtraField::FIELD_TYPE_TIMEZONE:
4662
                    $form->addElement('select', 'extra_'.$field_details[1], $field_details[3], api_get_timezones(), '');
4663
                    if ($field_details[7] == 0)
4664
                        $form->freeze('extra_'.$field_details[1]);
4665
                    break;
4666
                case ExtraField::FIELD_TYPE_SOCIAL_PROFILE:
4667
                    // get the social network's favicon
4668
                    $icon_path = UserManager::get_favicon_from_url($extra_data['extra_'.$field_details[1]], $field_details[4]);
4669
                    // special hack for hi5
4670
                    $leftpad = '1.7';
4671
                    $top = '0.4';
4672
                    $domain = parse_url($icon_path, PHP_URL_HOST);
4673
                    if ($domain == 'www.hi5.com' or $domain == 'hi5.com') {
4674
                        $leftpad = '3';
4675
                        $top = '0';
4676
                    }
4677
                    // print the input field
4678
                    $form->addElement(
4679
                        'text',
4680
                        'extra_'.$field_details[1],
4681
                        $field_details[3],
4682
                        array(
4683
                            'size' => 60,
4684
                            'style' => 'background-image: url(\''.$icon_path.'\'); background-repeat: no-repeat; background-position: 0.4em '.$top.'em; padding-left: '.$leftpad.'em; '
4685
                        )
4686
                    );
4687
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4688
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4689
                    if ($field_details[7] == 0)
4690
                        $form->freeze('extra_'.$field_details[1]);
4691
                    break;
4692
                case ExtraField::FIELD_TYPE_FILE:
4693
                    $extra_field = 'extra_'.$field_details[1];
4694
                    $form->addElement('file', $extra_field, $field_details[3], null, '');
4695
                    if ($extra_file_list = UserManager::build_user_extra_file_list($user_id, $field_details[1], '', true)) {
4696
                        $form->addElement('static', $extra_field . '_list', null, $extra_file_list);
4697
                    }
4698
                    if ($field_details[7] == 0) {
4699
                        $form->freeze($extra_field);
4700
                    }
4701
                    break;
4702 View Code Duplication
                case ExtraField::FIELD_TYPE_MOBILE_PHONE_NUMBER:
4703
                    $form->addElement(
4704
                        'text',
4705
                        'extra_'.$field_details[1],
4706
                        $field_details[3]." (".get_lang('CountryDialCode').")",
4707
                        array('size' => 40, 'placeholder'  => '(xx)xxxxxxxxx')
4708
                    );
4709
                    $form->applyFilter('extra_'.$field_details[1], 'stripslashes');
4710
                    $form->applyFilter('extra_'.$field_details[1], 'trim');
4711
                    $form->applyFilter('extra_'.$field_details[1], 'mobile_phone_number_filter');
4712
                    $form->addRule(
4713
                        'extra_'.$field_details[1],
4714
                        get_lang('MobilePhoneNumberWrong'),
4715
                        'mobile_phone_number'
4716
                    );
4717
                    if (!$admin_permissions) {
4718
                        if ($field_details[7] == 0) {
4719
                            $form->freeze('extra_'.$field_details[1]);
4720
                        }
4721
                    }
4722
                    break;
4723
            }
4724
        }
4725
        $return = array();
4726
        $return['jquery_ready_content'] = $jquery_ready_content;
4727
        return $return;
4728
    }
4729
4730
    /**
4731
     * @return array
4732
     */
4733
    static function get_user_field_types()
4734
    {
4735
        $types = array();
4736
        $types[self::USER_FIELD_TYPE_TEXT] = get_lang('FieldTypeText');
4737
        $types[self::USER_FIELD_TYPE_TEXTAREA] = get_lang('FieldTypeTextarea');
4738
        $types[self::USER_FIELD_TYPE_RADIO] = get_lang('FieldTypeRadio');
4739
        $types[self::USER_FIELD_TYPE_SELECT] = get_lang('FieldTypeSelect');
4740
        $types[self::USER_FIELD_TYPE_SELECT_MULTIPLE] = get_lang('FieldTypeSelectMultiple');
4741
        $types[self::USER_FIELD_TYPE_DATE] = get_lang('FieldTypeDate');
4742
        $types[self::USER_FIELD_TYPE_DATETIME] = get_lang('FieldTypeDatetime');
4743
        $types[self::USER_FIELD_TYPE_DOUBLE_SELECT] = get_lang('FieldTypeDoubleSelect');
4744
        $types[self::USER_FIELD_TYPE_DIVIDER] = get_lang('FieldTypeDivider');
4745
        $types[self::USER_FIELD_TYPE_TAG] = get_lang('FieldTypeTag');
4746
        $types[self::USER_FIELD_TYPE_TIMEZONE] = get_lang('FieldTypeTimezone');
4747
        $types[self::USER_FIELD_TYPE_SOCIAL_PROFILE] = get_lang('FieldTypeSocialProfile');
4748
        $types[self::USER_FIELD_TYPE_FILE] = get_lang('FieldTypeFile');
4749
        $types[self::USER_FIELD_TYPE_MOBILE_PHONE_NUMBER] = get_lang('FieldTypeMobilePhoneNumber');
4750
4751
        return $types;
4752
    }
4753
4754
    /**
4755
     * @param int $userId
4756
     */
4757 View Code Duplication
    static function add_user_as_admin($userId)
4758
    {
4759
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
4760
        $userId = intval($userId);
4761
4762
        if (!self::is_admin($userId)) {
4763
            $sql = "INSERT INTO $table_admin SET user_id = $userId";
4764
            Database::query($sql);
4765
        }
4766
    }
4767
4768
    /**
4769
     * @param int $userId
4770
     */
4771 View Code Duplication
    public static function remove_user_admin($userId)
4772
    {
4773
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
4774
        $userId = intval($userId);
4775
        if (self::is_admin($userId)) {
4776
            $sql = "DELETE FROM $table_admin WHERE user_id = $userId";
4777
            Database::query($sql);
4778
        }
4779
    }
4780
4781
    /**
4782
     * @param string $from
4783
     * @param string $to
4784
     */
4785
    public static function update_all_user_languages($from, $to)
4786
    {
4787
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4788
        $from = Database::escape_string($from);
4789
        $to = Database::escape_string($to);
4790
4791
        if (!empty($to) && !empty($from)) {
4792
            $sql = "UPDATE $table_user SET language = '$to'
4793
                    WHERE language = '$from'";
4794
            Database::query($sql);
4795
        }
4796
    }
4797
4798
    /**
4799
     * Subscribe users to student boss
4800
     * @param int $bossId The boss id
4801
     * @param array $usersId The users array
4802
     * @return int Affected rows
4803
     */
4804
    public static function subscribeUsersToBoss($bossId, $usersId)
4805
    {
4806
        return self::subscribeUsersToUser($bossId, $usersId, USER_RELATION_TYPE_BOSS);
4807
    }
4808
4809
    /**
4810
     * Get users followed by student boss
4811
     * @param int $userId
4812
     * @param int $userStatus (STUDENT, COURSEMANAGER, etc)
4813
     * @param bool $getOnlyUserId
4814
     * @param bool $getSql
4815
     * @param bool $getCount
4816
     * @param int $from
4817
     * @param int $numberItems
4818
     * @param int $column
4819
     * @param string $direction
4820
     * @param int $active
4821
     * @param string $lastConnectionDate
4822
     * @return array     users
4823
     */
4824 View Code Duplication
    public static function getUsersFollowedByStudentBoss(
4825
        $userId,
4826
        $userStatus = 0,
4827
        $getOnlyUserId = false,
4828
        $getSql = false,
4829
        $getCount = false,
4830
        $from = null,
4831
        $numberItems = null,
4832
        $column = null,
4833
        $direction = null,
4834
        $active = null,
4835
        $lastConnectionDate = null
4836
    ){
4837
        return self::getUsersFollowedByUser(
4838
                $userId, $userStatus, $getOnlyUserId, $getSql, $getCount, $from, $numberItems, $column, $direction,
4839
                $active, $lastConnectionDate, STUDENT_BOSS
4840
        );
4841
    }
4842
4843
    /**
4844
     * Get the teacher (users with COURSEMANGER status) list
4845
     * @return array The list
4846
     */
4847
    public static function getTeachersList()
4848
    {
4849
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4850
4851
        $resultData = Database::select('user_id, lastname, firstname, username', $userTable, array(
4852
            'where' => array(
4853
                'status = ?' => COURSEMANAGER
4854
            )
4855
        ));
4856
4857
        foreach ($resultData as &$teacherData) {
4858
            $teacherData['completeName'] = api_get_person_name($teacherData['firstname'], $teacherData['lastname']);
4859
        }
4860
4861
        return $resultData;
4862
    }
4863
4864
    /**
4865
     * @return array
4866
     */
4867 View Code Duplication
    public static function getOfficialCodeGrouped()
4868
    {
4869
        $user = Database::get_main_table(TABLE_MAIN_USER);
4870
        $sql = "SELECT DISTINCT official_code
4871
                FROM $user
4872
                GROUP BY official_code";
4873
        $result = Database::query($sql);
4874
4875
        $values = Database::store_result($result, 'ASSOC');
4876
4877
        $result = array();
4878
        foreach ($values as $value) {
4879
            $result[$value['official_code']] = $value['official_code'];
4880
        }
4881
        return $result;
4882
    }
4883
4884
    /**
4885
     * @param string $officialCode
4886
     * @return array
4887
     */
4888
    public static function getUsersByOfficialCode($officialCode)
4889
    {
4890
        $user = Database::get_main_table(TABLE_MAIN_USER);
4891
        $officialCode = Database::escape_string($officialCode);
4892
4893
        $sql = "SELECT DISTINCT id
4894
                FROM $user
4895
                WHERE official_code = '$officialCode'
4896
                ";
4897
        $result = Database::query($sql);
4898
4899
        $users = array();
4900
        while ($row = Database::fetch_array($result)) {
4901
            $users[] = $row['id'];
4902
        }
4903
        return $users;
4904
    }
4905
4906
    /**
4907
     * Calc the expended time (in seconds) by a user in a course
4908
     * @param int $userId The user id
4909
     * @param int $courseId The course id
4910
     * @param int $sessionId Optional. The session id
4911
     * @param string $from Optional. From date
4912
     * @param string $until Optional. Until date
4913
     * @return int The time
4914
     */
4915
    public static function getTimeSpentInCourses($userId, $courseId, $sessionId = 0, $from = '', $until = '')
4916
    {
4917
        $userId = intval($userId);
4918
        $sessionId = intval($sessionId);
4919
4920
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4921
4922
        $whereConditions = array(
4923
            'user_id = ? ' => $userId,
4924
            'AND c_id = ? ' => $courseId,
4925
            'AND session_id = ? ' => $sessionId
4926
        );
4927
4928 View Code Duplication
        if (!empty($from) && !empty($until)) {
4929
            $whereConditions["AND (login_course_date >= '?' "] = $from;
4930
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
4931
        }
4932
4933
        $trackResult = Database::select(
4934
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
4935
            $trackCourseAccessTable,
4936
            array(
4937
                'where' => $whereConditions
4938
            ), 'first'
4939
        );
4940
4941
        if ($trackResult != false) {
4942
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
4943
        }
4944
4945
        return 0;
4946
    }
4947
4948
    /**
4949
     * Get the boss user ID from a followed user id
4950
     * @param $userId
4951
     * @return bool
4952
     */
4953
    public static function getStudentBoss($userId)
4954
    {
4955
        $userId = intval($userId);
4956 View Code Duplication
        if ($userId > 0) {
4957
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4958
            $row = Database::select(
4959
                'DISTINCT friend_user_id AS boss_id',
4960
                $userRelTable,
4961
                array(
4962
                    'where' => array(
4963
                        'user_id = ? AND relation_type = ? LIMIT 1' => array(
4964
                            $userId,
4965
                            USER_RELATION_TYPE_BOSS,
4966
                        )
4967
                    )
4968
                )
4969
            );
4970
            if (!empty($row)) {
4971
4972
                return $row[0]['boss_id'];
4973
            }
4974
        }
4975
4976
        return false;
4977
    }
4978
4979
    /**
4980
     * Get either a Gravatar URL or complete image tag for a specified email address.
4981
     *
4982
     * @param string $email The email address
4983
     * @param string $s Size in pixels, defaults to 80px [ 1 - 2048 ]
4984
     * @param string $d Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
4985
     * @param string $r Maximum rating (inclusive) [ g | pg | r | x ]
4986
     * @param boole $img True to return a complete IMG tag False for just the URL
4987
     * @param array $atts Optional, additional key/value attributes to include in the IMG tag
4988
     * @return String containing either just a URL or a complete image tag
4989
     * @source http://gravatar.com/site/implement/images/php/
4990
     */
4991
    private static function getGravatar(
4992
        $email,
4993
        $s = 80,
4994
        $d = 'mm',
4995
        $r = 'g',
4996
        $img = false,
4997
        $atts = array()
4998
    ) {
4999
        $url = 'http://www.gravatar.com/avatar/';
5000
        if (!empty($_SERVER['HTTPS'])) {
5001
            $url = 'https://secure.gravatar.com/avatar/';
5002
        }
5003
        $url .= md5( strtolower( trim( $email ) ) );
5004
        $url .= "?s=$s&d=$d&r=$r";
5005
        if ( $img ) {
5006
            $url = '<img src="' . $url . '"';
5007
            foreach ( $atts as $key => $val )
5008
                $url .= ' ' . $key . '="' . $val . '"';
5009
            $url .= ' />';
5010
        }
5011
        return $url;
5012
    }
5013
5014
5015
5016
    /**
5017
     * Displays the name of the user and makes the link to the user profile
5018
     * @param array $userInfo
5019
     *
5020
     * @return string
5021
     */
5022
    public static function getUserProfileLink($userInfo)
5023
    {
5024
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5025
            return Display::url($userInfo['complete_name'], $userInfo['profile_url']);
5026
        } else {
5027
            return get_lang('Anonymous');
5028
        }
5029
    }
5030
5031
    /**
5032
     * Displays the name of the user and makes the link to the user profile
5033
     *
5034
     * @param $userInfo
5035
     *
5036
     * @return string
5037
     */
5038
    public static function getUserProfileLinkWithPicture($userInfo)
5039
    {
5040
        return Display::url(Display::img($userInfo['avatar']), $userInfo['profile_url']);
5041
    }
5042
5043
    /**
5044
     * Get users whose name matches $firstname and $lastname
5045
     * @param string $firstname Firstname to search
5046
     * @param string $lastname Lastname to search
5047
     * @return array The user list
5048
     */
5049 View Code Duplication
    public static function getUserByName($firstname, $lastname)
5050
    {
5051
        $firstname = Database::escape_string($firstname);
5052
        $lastname = Database::escape_string($lastname);
5053
5054
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5055
5056
        $sql = <<<SQL
5057
            SELECT id, username, lastname, firstname
5058
            FROM $userTable
5059
            WHERE firstname LIKE '$firstname%' AND
5060
                lastname LIKE '$lastname%'
5061
SQL;
5062
5063
        $result = Database::query($sql);
5064
5065
        $users = [];
5066
5067
        while ($resultData = Database::fetch_object($result)) {
5068
            $users[] = $resultData;
5069
        }
5070
5071
        return $users;
5072
    }
5073
5074
    /**
5075
     * @param int $optionSelected
5076
     * @return string
5077
     */
5078
    public static function getUserSubscriptionTab($optionSelected = 1)
5079
    {
5080
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5081
        if (($allowAdmin == 'true' && api_is_allowed_to_edit()) ||
5082
            api_is_platform_admin()
5083
        ) {
5084
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5085
5086
            $headers = [
5087
                [
5088
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5089
                    'content' => get_lang('Students'),
5090
                ],
5091
                [
5092
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5093
                    'content' => get_lang('Teachers'),
5094
                ],
5095
                /*[
5096
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5097
                    'content' => get_lang('Students'),
5098
                ],
5099
                [
5100
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5101
                    'content' => get_lang('Teachers'),
5102
                ],*/
5103
                [
5104
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5105
                    'content' => get_lang('Groups'),
5106
                ],
5107
                [
5108
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5109
                    'content' => get_lang('Classes'),
5110
                ],
5111
            ];
5112
5113
            return Display::tabsOnlyLink($headers, $optionSelected);
5114
        }
5115
    }
5116
5117
}
5118