Passed
Pull Request — 1.10.x (#986)
by
unknown
65:04
created

UserManager::searchUserByKeyword()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 10

Duplication

Lines 19
Ratio 100 %
Metric Value
dl 19
loc 19
rs 9.4285
cc 2
eloc 10
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
        global $_configuration;
479
        if (isset($_configuration['deny_delete_users']) &&
480
            $_configuration['deny_delete_users'] == true
481
        ) {
482
            return false;
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 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 ='".Database::escape_string($course->c_id)."'";
497
            $res2 = Database::query($sql);
498
            if (Database::num_rows($res2) == 1) {
499
                return false;
500
            }
501
        }
502
        return true;
503
    }
504
505
    /**
506
     * Delete a user from the platform, and all its belongings. This is a
507
     * very dangerous function that should only be accessible by
508
     * super-admins. Other roles should only be able to disable a user,
509
     * which removes access to the platform but doesn't delete anything.
510
     * @param int The ID of th user to be deleted
511
     * @return boolean true if user is successfully deleted, false otherwise
512
     * @assert (null) === false
513
     * @assert ('abc') === false
514
     */
515
    public static function delete_user($user_id)
516
    {
517
        if ($user_id != strval(intval($user_id))) {
518
            return false;
519
        }
520
521
        if ($user_id === false) {
522
            return false;
523
        }
524
525
        if (!self::can_delete_user($user_id)) {
526
            return false;
527
        }
528
529
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
530
        $usergroup_rel_user = Database :: get_main_table(TABLE_USERGROUP_REL_USER);
531
        $table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
532
        $table_course = Database :: get_main_table(TABLE_MAIN_COURSE);
533
        $table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
534
        $table_admin = Database :: get_main_table(TABLE_MAIN_ADMIN);
535
        $table_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
536
        $table_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
537
        $table_group = Database :: get_course_table(TABLE_GROUP_USER);
538
        $table_work = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
539
540
        // Unsubscribe the user from all groups in all his courses
541
        $sql = "SELECT c.id FROM $table_course c, $table_course_user cu
542
                WHERE
543
                    cu.user_id = '".$user_id."' AND
544
                    relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
545
                    c.id = cu.c_id";
546
547
        $res = Database::query($sql);
548
        while ($course = Database::fetch_object($res)) {
549
            $sql = "DELETE FROM $table_group
550
                    WHERE c_id = {$course->id} AND user_id = $user_id";
551
            Database::query($sql);
552
        }
553
554
        // Unsubscribe user from usergroup_rel_user
555
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
556
        Database::query($sql);
557
558
        // Unsubscribe user from all courses
559
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
560
        Database::query($sql);
561
562
        // Unsubscribe user from all courses in sessions
563
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
564
        Database::query($sql);
565
566
        // If the user was added as a id_coach then set the current admin as coach see BT#
567
        $currentUserId = api_get_user_id();
568
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
569
                WHERE id_coach = '".$user_id."'";
570
        Database::query($sql);
571
572
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
573
                WHERE session_admin_id = '".$user_id."'";
574
        Database::query($sql);
575
576
        // Unsubscribe user from all sessions
577
        $sql = "DELETE FROM $table_session_user
578
                WHERE user_id = '".$user_id."'";
579
        Database::query($sql);
580
581
        // Delete user picture
582
        /* TODO: Logic about api_get_setting('split_users_upload_directory') == 'true'
583
        a user has 4 different sized photos to be deleted. */
584
        $user_info = api_get_user_info($user_id);
585
586
        if (strlen($user_info['picture_uri']) > 0) {
587
            $path = self::getUserPathById($user_id, 'system');
588
            $img_path = $path.$user_info['picture_uri'];
589
            if (file_exists($img_path)) {
590
                unlink($img_path);
591
            }
592
        }
593
594
        // Delete the personal course categories
595
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
596
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
597
        Database::query($sql);
598
599
        // Delete user from the admin table
600
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
601
        Database::query($sql);
602
603
        // Delete the personal agenda-items from this user
604
        $agenda_table = Database :: get_main_table(TABLE_PERSONAL_AGENDA);
605
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
606
        Database::query($sql);
607
608
        $gradebook_results_table = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
609
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
610
        Database::query($sql);
611
612
        $extraFieldValue = new ExtraFieldValue('user');
613
        $extraFieldValue->deleteValuesByItem($user_id);
614
615
        $url_id = api_get_current_access_url_id();
616
        UrlManager::delete_url_rel_user($user_id, $url_id);
617
618
        if (api_get_setting('allow_social_tool') == 'true') {
619
            $userGroup = new UserGroup();
620
            //Delete user from portal groups
621
            $group_list = $userGroup->get_groups_by_user($user_id);
622
            if (!empty($group_list)) {
623
                foreach ($group_list as $group_id => $data) {
624
                    $userGroup->delete_user_rel_group($user_id, $group_id);
625
                }
626
            }
627
628
            // Delete user from friend lists
629
            SocialManager::remove_user_rel_user($user_id, true);
630
        }
631
632
        // Removing survey invitation
633
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
634
635
        // Delete students works
636
        $sql = "DELETE FROM $table_work WHERE user_id = $user_id AND c_id <> 0";
637
        Database::query($sql);
638
639
        $sql = "UPDATE c_item_property SET to_user_id = NULL
640
                WHERE to_user_id = '".$user_id."'";
641
        Database::query($sql);
642
643
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
644
                WHERE insert_user_id = '".$user_id."'";
645
        Database::query($sql);
646
647
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
648
                WHERE lastedit_user_id = '".$user_id."'";
649
        Database::query($sql);
650
651
        // Delete user from database
652
        $sql = "DELETE FROM $table_user WHERE id = '".$user_id."'";
653
        Database::query($sql);
654
655
656
657
        // Add event to system log
658
        $user_id_manager = api_get_user_id();
659
660
        Event::addEvent(
661
            LOG_USER_DELETE,
662
            LOG_USER_ID,
663
            $user_id,
664
            api_get_utc_datetime(),
665
            $user_id_manager
666
        );
667
668
        Event::addEvent(
669
            LOG_USER_DELETE,
670
            LOG_USER_OBJECT,
671
            $user_info,
672
            api_get_utc_datetime(),
673
            $user_id_manager
674
        );
675
676
        return true;
677
    }
678
679
    /**
680
     * Deletes users completely. Can be called either as:
681
     * - UserManager :: delete_users(1, 2, 3); or
682
     * - UserManager :: delete_users(array(1, 2, 3));
683
     * @param array|int $ids
684
     * @return boolean  True if at least one user was successfuly deleted. False otherwise.
685
     * @author Laurent Opprecht
686
     * @uses UserManager::delete_user() to actually delete each user
687
     * @assert (null) === false
688
     * @assert (-1) === false
689
     * @assert (array(-1)) === false
690
     */
691
    static function delete_users($ids = array())
692
    {
693
        $result = false;
694
        $ids = is_array($ids) ? $ids : func_get_args();
695
        if (!is_array($ids) or count($ids) == 0) { return false; }
696
        $ids = array_map('intval', $ids);
697
        foreach ($ids as $id) {
698
            if (empty($id) or $id < 1) { continue; }
699
            $deleted = self::delete_user($id);
700
            $result = $deleted || $result;
701
        }
702
703
        return $result;
704
    }
705
706
    /**
707
     * Disable users. Can be called either as:
708
     * - UserManager :: deactivate_users(1, 2, 3);
709
     * - UserManager :: deactivate_users(array(1, 2, 3));
710
     * @param array|int $ids
711
     * @return boolean
712
     * @author Laurent Opprecht
713
     * @assert (null) === false
714
     * @assert (array(-1)) === false
715
     */
716 View Code Duplication
    static function deactivate_users($ids = array())
717
    {
718
        if (empty($ids)) {
719
            return false;
720
        }
721
722
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
723
724
        $ids = is_array($ids) ? $ids : func_get_args();
725
        $ids = array_map('intval', $ids);
726
        $ids = implode(',', $ids);
727
728
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
729
        $r = Database::query($sql);
730
        if ($r !== false) {
731
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
732
        }
733
        return $r;
734
    }
735
736
    /**
737
     * Enable users. Can be called either as:
738
     * - UserManager :: activate_users(1, 2, 3);
739
     * - UserManager :: activate_users(array(1, 2, 3));
740
     * @param array|int IDs of the users to enable
741
     * @return boolean
742
     * @author Laurent Opprecht
743
     * @assert (null) === false
744
     * @assert (array(-1)) === false
745
     */
746 View Code Duplication
    static function activate_users($ids = array())
747
    {
748
        if (empty($ids)) {
749
            return false;
750
        }
751
752
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
753
754
        $ids = is_array($ids) ? $ids : func_get_args();
755
        $ids = array_map('intval', $ids);
756
        $ids = implode(',', $ids);
757
758
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
759
        $r = Database::query($sql);
760
        if ($r !== false) {
761
            Event::addEvent(LOG_USER_ENABLE,LOG_USER_ID,$ids);
762
        }
763
        return $r;
764
    }
765
766
    /**
767
     * Update user information with new openid
768
     * @param int $user_id
769
     * @param string $openid
770
     * @return boolean true if the user information was updated
771
     * @assert (false,'') === false
772
     * @assert (-1,'') === false
773
     */
774
    public static function update_openid($user_id, $openid)
775
    {
776
        $table_user = Database :: get_main_table(TABLE_MAIN_USER);
777
        if ($user_id != strval(intval($user_id)))
778
            return false;
779
        if ($user_id === false)
780
            return false;
781
        $sql = "UPDATE $table_user SET
782
                openid='".Database::escape_string($openid)."'";
783
        $sql .= " WHERE id= $user_id";
784
        return Database::query($sql);
785
    }
786
787
    /**
788
     * Update user information with all the parameters passed to this function
789
     * @param int The ID of the user to be updated
790
     * @param string The user's firstname
791
     * @param string The user's lastname
792
     * @param string The user's username (login)
793
     * @param string The user's password
794
     * @param string The authentication source (default: "platform")
795
     * @param string The user's e-mail address
796
     * @param int The user's status
797
     * @param string The user's official code (usually just an internal institutional code)
798
     * @param string The user's phone number
799
     * @param string The user's picture URL (internal to the Chamilo directory)
800
     * @param int The user ID of the person who registered this user (optional, defaults to null)
801
     * @param int The department of HR in which the user is registered (optional, defaults to 0)
802
     * @param array A series of additional fields to add to this user as extra fields (optional, defaults to null)
803
     * @return boolean true if the user information was updated
804
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
805
     */
806
    public static function update_user(
807
        $user_id,
808
        $firstname,
809
        $lastname,
810
        $username,
811
        $password = null,
812
        $auth_source = null,
813
        $email,
814
        $status,
815
        $official_code,
816
        $phone,
817
        $picture_uri,
818
        $expiration_date,
819
        $active,
820
        $creator_id = null,
821
        $hr_dept_id = 0,
822
        $extra = null,
823
        $language = 'english',
824
        $encrypt_method = '',
825
        $send_email = false,
826
        $reset_password = 0
827
    ) {
828
        $hook = HookUpdateUser::create();
829
        if (!empty($hook)) {
830
            $hook->notifyUpdateUser(HOOK_EVENT_TYPE_PRE);
831
        }
832
        global $_configuration;
833
        $original_password = $password;
834
835
        if (empty($user_id)) {
836
            return false;
837
        }
838
        $user_info = api_get_user_info($user_id, false, true);
839
840
        if ($reset_password == 0) {
841
            $password = null;
842
            $auth_source = $user_info['auth_source'];
843
        } elseif ($reset_password == 1) {
844
            $original_password = $password = api_generate_password();
845
            $auth_source = PLATFORM_AUTH_SOURCE;
846
        } elseif ($reset_password == 2) {
847
            $password = $password;
0 ignored issues
show
Bug introduced by
Why assign $password to itself?

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

This assignement can be removed without consequences.

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

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

This assignement can be removed without consequences.

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

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

This assignement can be removed without consequences.

Loading history...
852
        }
853
854
        if ($user_id != strval(intval($user_id))) {
855
            return false;
856
        }
857
858
        if ($user_id === false) {
859
            return false;
860
        }
861
862
        //Checking the user language
863
        $languages = api_get_languages();
864
        if (!in_array($language, $languages['folder'])) {
865
            $language = api_get_setting('platformLanguage');
866
        }
867
868
        $change_active = 0;
869
        if ($user_info['active'] != $active) {
870
            $change_active = 1;
871
        }
872
873
        $userManager = self::getManager();
874
875
        /** @var Chamilo\UserBundle\Entity\User $user */
876
        $user = self::getRepository()->find($user_id);
877
878
        if (empty($user)) {
879
            return false;
880
        }
881
882
        if (!empty($expiration_date)) {
883
            $expiration_date = api_get_utc_datetime($expiration_date);
884
            $expiration_date = new \DateTime(
885
                $expiration_date,
886
                new DateTimeZone('UTC')
887
            );
888
        }
889
890
        $user
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class FOS\UserBundle\Model\User as the method setStatus() does only exist in the following sub-classes of FOS\UserBundle\Model\User: Chamilo\UserBundle\Entity\User. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

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

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

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

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

Available Fixes

  1. Change the type-hint for the parameter:

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

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

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