Passed
Push — master ( af9f4d...a3d690 )
by Julito
12:39
created

api_block_inactive_user()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 42
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 26
c 0
b 0
f 0
nc 6
nop 0
dl 0
loc 42
rs 9.1928
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AccessUrl;
6
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

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...
7
use Chamilo\CoreBundle\Entity\Language;
8
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
9
use Chamilo\CoreBundle\Entity\SettingsCurrent;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\Entity\UserCourseCategory;
12
use Chamilo\CoreBundle\Framework\Container;
13
use Chamilo\CourseBundle\Entity\CGroup;
14
use Chamilo\CourseBundle\Entity\CLp;
15
use ChamiloSession as Session;
16
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
17
use Symfony\Component\Finder\Finder;
18
use Symfony\Component\Mime\Address;
19
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
20
use Symfony\Component\Security\Core\User\UserInterface;
21
use ZipStream\Option\Archive;
22
use ZipStream\ZipStream;
23
24
/**
25
 * This is a code library for Chamilo.
26
 * It is included by default in every Chamilo file (through including the global.inc.php)
27
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
28
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
29
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
30
 */
31
32
// PHP version requirement.
33
define('REQUIRED_PHP_VERSION', '8.0');
34
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
35
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
36
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
37
38
// USER STATUS CONSTANTS
39
/** global status of a user: student */
40
define('STUDENT', 5);
41
/** global status of a user: course manager */
42
define('COURSEMANAGER', 1);
43
/** global status of a user: session admin */
44
define('SESSIONADMIN', 3);
45
/** global status of a user: human ressource manager */
46
define('DRH', 4);
47
/** global status of a user: human ressource manager */
48
define('ANONYMOUS', 6);
49
/** global status of a user: low security, necessary for inserting data from
50
 * the teacher through HTMLPurifier */
51
define('COURSEMANAGERLOWSECURITY', 10);
52
// Soft user status
53
define('PLATFORM_ADMIN', 11);
54
define('SESSION_COURSE_COACH', 12);
55
define('SESSION_GENERAL_COACH', 13);
56
define('COURSE_STUDENT', 14); //student subscribed in a course
57
define('SESSION_STUDENT', 15); //student subscribed in a session course
58
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
59
define('STUDENT_BOSS', 17); // student is boss
60
define('INVITEE', 20);
61
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
62
63
// COURSE VISIBILITY CONSTANTS
64
/** only visible for course admin */
65
define('COURSE_VISIBILITY_CLOSED', 0);
66
/** only visible for users registered in the course */
67
define('COURSE_VISIBILITY_REGISTERED', 1);
68
/** Open for all registered users on the platform */
69
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
70
/** Open for the whole world */
71
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
72
/** Invisible to all except admin */
73
define('COURSE_VISIBILITY_HIDDEN', 4);
74
75
define('COURSE_REQUEST_PENDING', 0);
76
define('COURSE_REQUEST_ACCEPTED', 1);
77
define('COURSE_REQUEST_REJECTED', 2);
78
define('DELETE_ACTION_ENABLED', false);
79
80
// EMAIL SENDING RECIPIENT CONSTANTS
81
define('SEND_EMAIL_EVERYONE', 1);
82
define('SEND_EMAIL_STUDENTS', 2);
83
define('SEND_EMAIL_TEACHERS', 3);
84
85
// SESSION VISIBILITY CONSTANTS
86
define('SESSION_VISIBLE_READ_ONLY', 1);
87
define('SESSION_VISIBLE', 2);
88
define('SESSION_INVISIBLE', 3); // not available
89
define('SESSION_AVAILABLE', 4);
90
91
define('SESSION_LINK_TARGET', '_self');
92
93
define('SUBSCRIBE_ALLOWED', 1);
94
define('SUBSCRIBE_NOT_ALLOWED', 0);
95
define('UNSUBSCRIBE_ALLOWED', 1);
96
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
97
98
// SURVEY VISIBILITY CONSTANTS
99
define('SURVEY_VISIBLE_TUTOR', 0);
100
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
101
define('SURVEY_VISIBLE_PUBLIC', 2);
102
103
// CONSTANTS defining all tools, using the english version
104
/* When you add a new tool you must add it into function api_get_tools_lists() too */
105
define('TOOL_DOCUMENT', 'document');
106
define('TOOL_LP_FINAL_ITEM', 'final_item');
107
define('TOOL_READOUT_TEXT', 'readout_text');
108
define('TOOL_THUMBNAIL', 'thumbnail');
109
define('TOOL_HOTPOTATOES', 'hotpotatoes');
110
define('TOOL_CALENDAR_EVENT', 'calendar_event');
111
define('TOOL_LINK', 'link');
112
define('TOOL_LINK_CATEGORY', 'link_category');
113
define('TOOL_COURSE_DESCRIPTION', 'course_description');
114
define('TOOL_SEARCH', 'search');
115
define('TOOL_LEARNPATH', 'learnpath');
116
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
117
define('TOOL_AGENDA', 'agenda');
118
define('TOOL_ANNOUNCEMENT', 'announcement');
119
define('TOOL_FORUM', 'forum');
120
define('TOOL_FORUM_CATEGORY', 'forum_category');
121
define('TOOL_FORUM_THREAD', 'forum_thread');
122
define('TOOL_FORUM_POST', 'forum_post');
123
define('TOOL_FORUM_ATTACH', 'forum_attachment');
124
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
125
define('TOOL_THREAD', 'thread');
126
define('TOOL_POST', 'post');
127
define('TOOL_DROPBOX', 'dropbox');
128
define('TOOL_QUIZ', 'quiz');
129
define('TOOL_TEST_CATEGORY', 'test_category');
130
define('TOOL_USER', 'user');
131
define('TOOL_GROUP', 'group');
132
define('TOOL_BLOGS', 'blog_management');
133
define('TOOL_CHAT', 'chat');
134
define('TOOL_STUDENTPUBLICATION', 'student_publication');
135
define('TOOL_TRACKING', 'tracking');
136
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
137
define('TOOL_COURSE_SETTING', 'course_setting');
138
define('TOOL_BACKUP', 'backup');
139
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
140
define('TOOL_RECYCLE_COURSE', 'recycle_course');
141
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
142
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
143
define('TOOL_UPLOAD', 'file_upload');
144
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
145
define('TOOL_SURVEY', 'survey');
146
//define('TOOL_WIKI', 'wiki');
147
define('TOOL_GLOSSARY', 'glossary');
148
define('TOOL_GRADEBOOK', 'gradebook');
149
define('TOOL_NOTEBOOK', 'notebook');
150
define('TOOL_ATTENDANCE', 'attendance');
151
define('TOOL_COURSE_PROGRESS', 'course_progress');
152
define('TOOL_PORTFOLIO', 'portfolio');
153
define('TOOL_PLAGIARISM', 'compilatio');
154
define('TOOL_XAPI', 'xapi');
155
156
// CONSTANTS defining Chamilo interface sections
157
define('SECTION_CAMPUS', 'mycampus');
158
define('SECTION_COURSES', 'mycourses');
159
define('SECTION_CATALOG', 'catalog');
160
define('SECTION_MYPROFILE', 'myprofile');
161
define('SECTION_MYAGENDA', 'myagenda');
162
define('SECTION_COURSE_ADMIN', 'course_admin');
163
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
164
define('SECTION_MYGRADEBOOK', 'mygradebook');
165
define('SECTION_TRACKING', 'session_my_space');
166
define('SECTION_SOCIAL', 'social-network');
167
define('SECTION_DASHBOARD', 'dashboard');
168
define('SECTION_REPORTS', 'reports');
169
define('SECTION_GLOBAL', 'global');
170
define('SECTION_INCLUDE', 'include');
171
define('SECTION_CUSTOMPAGE', 'custompage');
172
173
// CONSTANT name for local authentication source
174
define('PLATFORM_AUTH_SOURCE', 'platform');
175
define('CAS_AUTH_SOURCE', 'cas');
176
define('LDAP_AUTH_SOURCE', 'extldap');
177
178
// event logs types
179
define('LOG_COURSE_DELETE', 'course_deleted');
180
define('LOG_COURSE_CREATE', 'course_created');
181
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
182
183
// @todo replace 'soc_gr' with social_group
184
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
185
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
186
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
187
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
188
189
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
190
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
191
192
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
193
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
194
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
195
196
define('LOG_USER_DELETE', 'user_deleted');
197
define('LOG_USER_CREATE', 'user_created');
198
define('LOG_USER_UPDATE', 'user_updated');
199
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
200
define('LOG_USER_ENABLE', 'user_enable');
201
define('LOG_USER_DISABLE', 'user_disable');
202
define('LOG_USER_ANONYMIZE', 'user_anonymized');
203
define('LOG_USER_FIELD_CREATE', 'user_field_created');
204
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
205
define('LOG_SESSION_CREATE', 'session_created');
206
define('LOG_SESSION_DELETE', 'session_deleted');
207
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
208
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
209
define('LOG_SESSION_ADD_USER', 'session_add_user');
210
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
211
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
212
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
213
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
214
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
215
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
216
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
217
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
218
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
219
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
220
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
221
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
222
define('LOG_PROMOTION_CREATE', 'promotion_created');
223
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
224
define('LOG_CAREER_CREATE', 'career_created');
225
define('LOG_CAREER_DELETE', 'career_deleted');
226
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
227
//define('LOG_WIKI_ACCESS', 'wiki_page_view');
228
// All results from an exercise
229
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
230
// Logs only the one attempt
231
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
232
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
233
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
234
define('LOG_QUESTION_SCORE_UPDATE', 'score_attempt_updated');
235
236
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
237
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
238
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
239
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
240
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
241
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
242
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
243
244
// Event logs data types (max 20 chars)
245
define('LOG_COURSE_CODE', 'course_code');
246
define('LOG_COURSE_ID', 'course_id');
247
define('LOG_USER_ID', 'user_id');
248
define('LOG_USER_OBJECT', 'user_object');
249
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
250
define('LOG_SESSION_ID', 'session_id');
251
252
define('LOG_QUESTION_ID', 'question_id');
253
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
254
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
255
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
256
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
257
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
258
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
259
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
260
define('LOG_CAREER_ID', 'career_id');
261
define('LOG_PROMOTION_ID', 'promotion_id');
262
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
263
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
264
define('LOG_GRADEBOOK_ID', 'gradebook_id');
265
//define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
266
define('LOG_EXERCISE_ID', 'exercise_id');
267
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
268
define('LOG_LP_ID', 'lp_id');
269
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
270
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
271
272
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
273
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
274
define('LOG_WORK_DATA', 'work_data_array');
275
276
define('LOG_MY_FOLDER_PATH', 'path');
277
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
278
279
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
280
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
281
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
282
283
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
284
285
define('LOG_QUESTION_CREATED', 'question_created');
286
define('LOG_QUESTION_UPDATED', 'question_updated');
287
define('LOG_QUESTION_DELETED', 'question_deleted');
288
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
289
290
define('LOG_SURVEY_ID', 'survey_id');
291
define('LOG_SURVEY_CREATED', 'survey_created');
292
define('LOG_SURVEY_DELETED', 'survey_deleted');
293
define('LOG_SURVEY_CLEAN_RESULTS', 'survey_clean_results');
294
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.\$-]/');
295
296
//used when login_is_email setting is true
297
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
298
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
299
300
// This constant is a result of Windows OS detection, it has a boolean value:
301
// true whether the server runs on Windows OS, false otherwise.
302
define('IS_WINDOWS_OS', api_is_windows_os());
303
304
// Patterns for processing paths. Examples.
305
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
306
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
307
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
308
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
309
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
310
// basic (leaf elements)
311
define('REL_CODE_PATH', 'REL_CODE_PATH');
312
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
313
define('REL_HOME_PATH', 'REL_HOME_PATH');
314
315
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
316
define('WEB_PATH', 'WEB_PATH');
317
define('SYS_PATH', 'SYS_PATH');
318
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
319
320
define('REL_PATH', 'REL_PATH');
321
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
322
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
323
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
324
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
325
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
326
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
327
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
328
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
329
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
330
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
331
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
332
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
333
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
334
define('LIBRARY_PATH', 'LIBRARY_PATH');
335
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
336
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
337
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
338
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
339
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
340
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
341
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
342
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
343
344
// Relations type with Course manager
345
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
346
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
347
348
// Relations type with Human resources manager
349
define('COURSE_RELATION_TYPE_RRHH', 1);
350
define('SESSION_RELATION_TYPE_RRHH', 1);
351
352
// User image sizes
353
define('USER_IMAGE_SIZE_ORIGINAL', 1);
354
define('USER_IMAGE_SIZE_BIG', 2);
355
define('USER_IMAGE_SIZE_MEDIUM', 3);
356
define('USER_IMAGE_SIZE_SMALL', 4);
357
358
// Relation type between users
359
define('USER_UNKNOWN', 0);
360
define('USER_RELATION_TYPE_UNKNOWN', 1);
361
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
362
define('USER_RELATION_TYPE_FRIEND', 3);
363
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
364
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
365
define('USER_RELATION_TYPE_DELETED', 6);
366
define('USER_RELATION_TYPE_RRHH', 7);
367
define('USER_RELATION_TYPE_BOSS', 8);
368
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
369
370
// Gradebook link constants
371
// Please do not change existing values, they are used in the database !
372
define('GRADEBOOK_ITEM_LIMIT', 1000);
373
374
define('LINK_EXERCISE', 1);
375
define('LINK_DROPBOX', 2);
376
define('LINK_STUDENTPUBLICATION', 3);
377
define('LINK_LEARNPATH', 4);
378
define('LINK_FORUM_THREAD', 5);
379
//define('LINK_WORK',6);
380
define('LINK_ATTENDANCE', 7);
381
define('LINK_SURVEY', 8);
382
define('LINK_HOTPOTATOES', 9);
383
define('LINK_PORTFOLIO', 10);
384
385
// Score display types constants
386
define('SCORE_DIV', 1); // X / Y
387
define('SCORE_PERCENT', 2); // XX %
388
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
389
define('SCORE_AVERAGE', 4); // XX %
390
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
391
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
392
define('SCORE_SIMPLE', 7); // X
393
define('SCORE_IGNORE_SPLIT', 8); //  ??
394
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
395
define('SCORE_CUSTOM', 10); // Good!
396
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
397
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
398
define('SCORE_ONLY_SCORE', 13); // X - Good!
399
define('SCORE_NUMERIC', 14);
400
401
define('SCORE_BOTH', 1);
402
define('SCORE_ONLY_DEFAULT', 2);
403
define('SCORE_ONLY_CUSTOM', 3);
404
405
// From display.lib.php
406
407
define('MAX_LENGTH_BREADCRUMB', 100);
408
define('ICON_SIZE_ATOM', 8);
409
define('ICON_SIZE_TINY', 16);
410
define('ICON_SIZE_SMALL', 22);
411
define('ICON_SIZE_MEDIUM', 32);
412
define('ICON_SIZE_LARGE', 48);
413
define('ICON_SIZE_BIG', 64);
414
define('ICON_SIZE_HUGE', 128);
415
define('SHOW_TEXT_NEAR_ICONS', false);
416
417
// Session catalog
418
define('CATALOG_COURSES', 0);
419
define('CATALOG_SESSIONS', 1);
420
define('CATALOG_COURSES_SESSIONS', 2);
421
422
// Hook type events, pre-process and post-process.
423
// All means to be executed for both hook event types
424
define('HOOK_EVENT_TYPE_PRE', 0);
425
define('HOOK_EVENT_TYPE_POST', 1);
426
define('HOOK_EVENT_TYPE_ALL', 10);
427
428
// Group permissions
429
define('GROUP_PERMISSION_OPEN', '1');
430
define('GROUP_PERMISSION_CLOSED', '2');
431
432
// Group user permissions
433
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
434
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
435
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
436
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
437
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
438
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
439
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
440
441
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
442
define('GROUP_IMAGE_SIZE_BIG', 2);
443
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
444
define('GROUP_IMAGE_SIZE_SMALL', 4);
445
define('GROUP_TITLE_LENGTH', 50);
446
447
// Exercise
448
// @todo move into a class
449
define('ALL_ON_ONE_PAGE', 1);
450
define('ONE_PER_PAGE', 2);
451
452
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
453
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
454
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
455
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
456
457
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
458
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
459
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
460
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
461
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
462
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
463
define('RESULT_DISABLE_RANKING', 6);
464
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
465
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
466
define('RESULT_DISABLE_RADAR', 9);
467
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT_NO_FEEDBACK', 10);
468
469
define('EXERCISE_MAX_NAME_SIZE', 80);
470
471
// Question types (edit next array as well when adding values)
472
// @todo move into a class
473
define('UNIQUE_ANSWER', 1);
474
define('MULTIPLE_ANSWER', 2);
475
define('FILL_IN_BLANKS', 3);
476
define('MATCHING', 4);
477
define('FREE_ANSWER', 5);
478
define('HOT_SPOT', 6);
479
define('HOT_SPOT_ORDER', 7);
480
define('HOT_SPOT_DELINEATION', 8);
481
define('MULTIPLE_ANSWER_COMBINATION', 9);
482
define('UNIQUE_ANSWER_NO_OPTION', 10);
483
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
484
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
485
define('ORAL_EXPRESSION', 13);
486
define('GLOBAL_MULTIPLE_ANSWER', 14);
487
define('MEDIA_QUESTION', 15);
488
define('CALCULATED_ANSWER', 16);
489
define('UNIQUE_ANSWER_IMAGE', 17);
490
define('DRAGGABLE', 18);
491
define('MATCHING_DRAGGABLE', 19);
492
define('ANNOTATION', 20);
493
define('READING_COMPREHENSION', 21);
494
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
495
496
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
497
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
498
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
499
500
// Question selection type
501
define('EX_Q_SELECTION_ORDERED', 1);
502
define('EX_Q_SELECTION_RANDOM', 2);
503
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
504
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
505
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
506
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
507
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
508
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
509
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
510
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
511
512
// Used to save the skill_rel_item table
513
define('ITEM_TYPE_EXERCISE', 1);
514
define('ITEM_TYPE_HOTPOTATOES', 2);
515
define('ITEM_TYPE_LINK', 3);
516
define('ITEM_TYPE_LEARNPATH', 4);
517
define('ITEM_TYPE_GRADEBOOK', 5);
518
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
519
//define('ITEM_TYPE_FORUM', 7);
520
define('ITEM_TYPE_ATTENDANCE', 8);
521
define('ITEM_TYPE_SURVEY', 9);
522
define('ITEM_TYPE_FORUM_THREAD', 10);
523
define('ITEM_TYPE_PORTFOLIO', 11);
524
525
// Course description blocks.
526
define('ADD_BLOCK', 8);
527
528
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
529
define(
530
    'QUESTION_TYPES',
531
    UNIQUE_ANSWER.':'.
532
    MULTIPLE_ANSWER.':'.
533
    FILL_IN_BLANKS.':'.
534
    MATCHING.':'.
535
    FREE_ANSWER.':'.
536
    HOT_SPOT.':'.
537
    HOT_SPOT_ORDER.':'.
538
    HOT_SPOT_DELINEATION.':'.
539
    MULTIPLE_ANSWER_COMBINATION.':'.
540
    UNIQUE_ANSWER_NO_OPTION.':'.
541
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
542
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
543
    ORAL_EXPRESSION.':'.
544
    GLOBAL_MULTIPLE_ANSWER.':'.
545
    MEDIA_QUESTION.':'.
546
    CALCULATED_ANSWER.':'.
547
    UNIQUE_ANSWER_IMAGE.':'.
548
    DRAGGABLE.':'.
549
    MATCHING_DRAGGABLE.':'.
550
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
551
    ANNOTATION
552
);
553
554
//Some alias used in the QTI exports
555
define('MCUA', 1);
556
define('TF', 1);
557
define('MCMA', 2);
558
define('FIB', 3);
559
560
// Message
561
define('MESSAGE_STATUS_NEW', 0);
562
define('MESSAGE_STATUS_UNREAD', 1);
563
//2 ??
564
define('MESSAGE_STATUS_DELETED', 3);
565
define('MESSAGE_STATUS_OUTBOX', 4);
566
define('MESSAGE_STATUS_INVITATION_PENDING', 5);
567
define('MESSAGE_STATUS_INVITATION_ACCEPTED', 6);
568
define('MESSAGE_STATUS_INVITATION_DENIED', 7);
569
define('MESSAGE_STATUS_WALL', 8);
570
define('MESSAGE_STATUS_WALL_DELETE', 9);
571
define('MESSAGE_STATUS_WALL_POST', 10);
572
define('MESSAGE_STATUS_CONVERSATION', 11);
573
define('MESSAGE_STATUS_FORUM', 12);
574
define('MESSAGE_STATUS_PROMOTED', 13);
575
576
// Images
577
define('IMAGE_WALL_SMALL_SIZE', 200);
578
define('IMAGE_WALL_MEDIUM_SIZE', 500);
579
define('IMAGE_WALL_BIG_SIZE', 2000);
580
define('IMAGE_WALL_SMALL', 'small');
581
define('IMAGE_WALL_MEDIUM', 'medium');
582
define('IMAGE_WALL_BIG', 'big');
583
584
// Social PLUGIN PLACES
585
define('SOCIAL_LEFT_PLUGIN', 1);
586
define('SOCIAL_CENTER_PLUGIN', 2);
587
define('SOCIAL_RIGHT_PLUGIN', 3);
588
define('CUT_GROUP_NAME', 50);
589
590
/**
591
 * FormValidator Filter.
592
 */
593
define('NO_HTML', 1);
594
define('STUDENT_HTML', 2);
595
define('TEACHER_HTML', 3);
596
define('STUDENT_HTML_FULLPAGE', 4);
597
define('TEACHER_HTML_FULLPAGE', 5);
598
599
// Timeline
600
define('TIMELINE_STATUS_ACTIVE', '1');
601
define('TIMELINE_STATUS_INACTIVE', '2');
602
603
// Event email template class
604
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
605
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
606
607
// Course home
608
define('SHORTCUTS_HORIZONTAL', 0);
609
define('SHORTCUTS_VERTICAL', 1);
610
611
// Course copy
612
define('FILE_SKIP', 1);
613
define('FILE_RENAME', 2);
614
define('FILE_OVERWRITE', 3);
615
define('UTF8_CONVERT', false); //false by default
616
617
define('DOCUMENT', 'file');
618
define('FOLDER', 'folder');
619
620
define('RESOURCE_ASSET', 'asset');
621
define('RESOURCE_DOCUMENT', 'document');
622
define('RESOURCE_GLOSSARY', 'glossary');
623
define('RESOURCE_EVENT', 'calendar_event');
624
define('RESOURCE_LINK', 'link');
625
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
626
define('RESOURCE_LEARNPATH', 'learnpath');
627
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
628
define('RESOURCE_ANNOUNCEMENT', 'announcement');
629
define('RESOURCE_FORUM', 'forum');
630
define('RESOURCE_FORUMTOPIC', 'thread');
631
define('RESOURCE_FORUMPOST', 'post');
632
define('RESOURCE_QUIZ', 'quiz');
633
define('RESOURCE_TEST_CATEGORY', 'test_category');
634
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
635
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
636
define('RESOURCE_LINKCATEGORY', 'Link_Category');
637
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
638
define('RESOURCE_SCORM', 'Scorm');
639
define('RESOURCE_SURVEY', 'survey');
640
define('RESOURCE_SURVEYQUESTION', 'survey_question');
641
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
642
//define('RESOURCE_WIKI', 'wiki');
643
define('RESOURCE_THEMATIC', 'thematic');
644
define('RESOURCE_ATTENDANCE', 'attendance');
645
define('RESOURCE_WORK', 'work');
646
define('RESOURCE_SESSION_COURSE', 'session_course');
647
define('RESOURCE_GRADEBOOK', 'gradebook');
648
define('ADD_THEMATIC_PLAN', 6);
649
650
// Max online users to show per page (whoisonline)
651
define('MAX_ONLINE_USERS', 12);
652
653
define('TOOL_AUTHORING', 'toolauthoring');
654
define('TOOL_INTERACTION', 'toolinteraction');
655
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
656
define('TOOL_ADMIN', 'tooladmin');
657
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
658
define('TOOL_DRH', 'tool_drh');
659
define('TOOL_STUDENT_VIEW', 'toolstudentview');
660
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
661
662
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
663
// some constants to avoid serialize string keys on serialized data array
664
define('SE_COURSE_ID', 0);
665
define('SE_TOOL_ID', 1);
666
define('SE_DATA', 2);
667
define('SE_USER', 3);
668
669
// in some cases we need top differenciate xapian documents of the same tool
670
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
671
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
672
673
// xapian prefixes
674
define('XAPIAN_PREFIX_COURSEID', 'C');
675
define('XAPIAN_PREFIX_TOOLID', 'O');
676
677
/**
678
 * Returns a path to a certain resource within Chamilo.
679
 * @param string $path A path which type is to be converted. Also, it may be a defined constant for a path.
680
 *
681
 * @return string the requested path or the converted path
682
 *
683
 * Notes about the current behaviour model:
684
 * 1. Windows back-slashes are converted to slashes in the result.
685
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
686
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
687
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
688
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
689
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
690
 * It has not been identified as needed yet.
691
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
692
 *
693
 * Vchamilo changes : allow using an alternate configuration
694
 * to get vchamilo  instance paths
695
 */
696
function api_get_path($path = '', $configuration = [])
697
{
698
    global $paths;
699
700
    // get proper configuration data if exists
701
    global $_configuration;
702
703
    $emptyConfigurationParam = false;
704
    if (empty($configuration)) {
705
        $configuration = (array) $_configuration;
706
        $emptyConfigurationParam = true;
707
    }
708
709
    $root_sys = Container::getProjectDir();
710
    $root_web = '';
711
    if (isset(Container::$container)) {
712
        $root_web = Container::$container->get('router')->generate(
713
            'index',
714
            [],
715
            UrlGeneratorInterface::ABSOLUTE_URL
716
        );
717
    }
718
719
    if (isset($configuration['multiple_access_urls']) &&
720
        $configuration['multiple_access_urls']
721
    ) {
722
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
723
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
724
            // We look into the DB the function api_get_access_url
725
            $urlInfo = api_get_access_url($configuration['access_url']);
726
            // Avoid default value
727
            $defaultValues = ['http://localhost/', 'https://localhost/'];
728
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
729
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
730
            }
731
        }
732
    }
733
734
    $paths = [
735
        WEB_PATH => $root_web,
736
        SYMFONY_SYS_PATH => $root_sys,
737
        SYS_PATH => $root_sys.'public/',
738
        REL_PATH => '',
739
        CONFIGURATION_PATH => 'app/config/',
740
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
741
742
        REL_COURSE_PATH => '',
743
        REL_CODE_PATH => '/main/',
744
745
        SYS_CODE_PATH => $root_sys.'public/main/',
746
        SYS_CSS_PATH => $root_sys.'public/build/css/',
747
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
748
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
749
        SYS_TEST_PATH => $root_sys.'tests/',
750
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
751
        SYS_PUBLIC_PATH => $root_sys.'public/',
752
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
753
754
        WEB_CODE_PATH => $root_web.'main/',
755
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
756
        WEB_COURSE_PATH => $root_web.'course/',
757
        WEB_IMG_PATH => $root_web.'img/',
758
        WEB_CSS_PATH => $root_web.'build/css/',
759
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
760
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
761
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
762
        WEB_PLUGIN_PATH => $root_web.'plugin/',
763
        WEB_PUBLIC_PATH => $root_web,
764
    ];
765
766
    $root_rel = '';
767
768
    global $virtualChamilo;
769
    if (!empty($virtualChamilo)) {
770
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
771
        //$paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
772
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
773
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
774
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
775
776
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
777
778
        // RewriteEngine On
779
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
780
781
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
782
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
783
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
784
    }
785
786
    $path = trim($path);
787
788
    // Retrieving a common-purpose path.
789
    if (isset($paths[$path])) {
790
        return $paths[$path];
791
    }
792
793
    return false;
794
}
795
796
/**
797
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
798
 *
799
 * @param string $path the input path
800
 *
801
 * @return string returns the modified path
802
 */
803
function api_add_trailing_slash($path)
804
{
805
    return '/' === substr($path, -1) ? $path : $path.'/';
806
}
807
808
/**
809
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
810
 *
811
 * @param string $path the input path
812
 *
813
 * @return string returns the modified path
814
 */
815
function api_remove_trailing_slash($path)
816
{
817
    return '/' === substr($path, -1) ? substr($path, 0, -1) : $path;
818
}
819
820
/**
821
 * Checks the RFC 3986 syntax of a given URL.
822
 *
823
 * @param string $url      the URL to be checked
824
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
825
 *
826
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
827
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
828
 *
829
 * @see http://drupal.org
830
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
831
 * @see http://bugs.php.net/51192
832
 */
833
function api_valid_url($url, $absolute = false)
834
{
835
    if ($absolute) {
836
        if (preg_match("
837
            /^                                                      # Start at the beginning of the text
838
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
839
            (?:                                                     # Userinfo (optional) which is typically
840
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
841
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
842
            )?
843
            (?:
844
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
845
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
846
            )
847
            (?::[0-9]+)?                                            # Server port number (optional)
848
            (?:[\/|\?]
849
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
850
            *)?
851
            $/xi", $url)) {
852
            return $url;
853
        }
854
855
        return false;
856
    } else {
857
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
858
    }
859
}
860
861
/**
862
 * Checks whether a given string looks roughly like an email address.
863
 *
864
 * @param string $address the e-mail address to be checked
865
 *
866
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
867
 */
868
function api_valid_email($address)
869
{
870
    return filter_var($address, FILTER_VALIDATE_EMAIL);
871
}
872
873
/**
874
 * Function used to protect a course script.
875
 * The function blocks access when
876
 * - there is no $_SESSION["_course"] defined; or
877
 * - $is_allowed_in_course is set to false (this depends on the course
878
 * visibility and user status).
879
 *
880
 * This is only the first proposal, test and improve!
881
 *
882
 * @param bool Option to print headers when displaying error message. Default: false
883
 * @param bool whether session admins should be allowed or not
884
 * @param string $checkTool check if tool is available for users (user, group)
885
 *
886
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
887
 *
888
 * @todo replace global variable
889
 *
890
 * @author Roan Embrechts
891
 */
892
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
893
{
894
    $course_info = api_get_course_info();
895
    if (empty($course_info)) {
896
        api_not_allowed($print_headers);
897
898
        return false;
899
    }
900
901
    if (api_is_drh()) {
902
        return true;
903
    }
904
905
    // Session admin has access to course
906
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
907
    if ($sessionAccess) {
908
        $allow_session_admins = true;
909
    }
910
911
    if (api_is_platform_admin($allow_session_admins)) {
912
        return true;
913
    }
914
915
    $isAllowedInCourse = api_is_allowed_in_course();
916
    $is_visible = false;
917
    if (isset($course_info) && isset($course_info['visibility'])) {
918
        switch ($course_info['visibility']) {
919
            default:
920
            case Course::CLOSED:
921
                // Completely closed: the course is only accessible to the teachers. - 0
922
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
923
                    $is_visible = true;
924
                }
925
                break;
926
            case Course::REGISTERED:
927
                // Private - access authorized to course members only - 1
928
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
929
                    $is_visible = true;
930
                }
931
                break;
932
            case Course::OPEN_PLATFORM:
933
                // Open - access allowed for users registered on the platform - 2
934
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
935
                    $is_visible = true;
936
                }
937
                break;
938
            case Course::OPEN_WORLD:
939
                //Open - access allowed for the whole world - 3
940
                $is_visible = true;
941
                break;
942
            case Course::HIDDEN:
943
                //Completely closed: the course is only accessible to the teachers. - 0
944
                if (api_is_platform_admin()) {
945
                    $is_visible = true;
946
                }
947
                break;
948
        }
949
950
        //If password is set and user is not registered to the course then the course is not visible
951
        if (false === $isAllowedInCourse &&
952
            isset($course_info['registration_code']) &&
953
            !empty($course_info['registration_code'])
954
        ) {
955
            $is_visible = false;
956
        }
957
    }
958
959
    if (!empty($checkTool)) {
960
        if (!api_is_allowed_to_edit(true, true, true)) {
961
            $toolInfo = api_get_tool_information_by_name($checkTool);
962
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
963
                api_not_allowed(true);
964
965
                return false;
966
            }
967
        }
968
    }
969
970
    // Check session visibility
971
    $session_id = api_get_session_id();
972
973
    if (!empty($session_id)) {
974
        // $isAllowedInCourse was set in local.inc.php
975
        if (!$isAllowedInCourse) {
976
            $is_visible = false;
977
        }
978
        // Check if course is inside session.
979
        if (!SessionManager::relation_session_course_exist($session_id, $course_info['real_id'])) {
980
            $is_visible = false;
981
        }
982
    }
983
984
    if (!$is_visible) {
985
        api_not_allowed($print_headers);
986
987
        return false;
988
    }
989
990
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
991
        $plugin = Positioning::create();
992
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
993
        if ('true' === $block) {
994
            $currentPath = $_SERVER['PHP_SELF'];
995
            // Allowed only this course paths.
996
            $paths = [
997
                '/plugin/positioning/start.php',
998
                '/plugin/positioning/start_student.php',
999
                '/main/course_home/course_home.php',
1000
                '/main/exercise/overview.php',
1001
            ];
1002
1003
            if (!in_array($currentPath, $paths, true)) {
1004
                // Check if entering an exercise.
1005
                // @todo remove global $current_course_tool
1006
                /*global $current_course_tool;
1007
                if ('quiz' !== $current_course_tool) {
1008
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1009
                    if ($initialData && isset($initialData['exercise_id'])) {
1010
                        $results = Event::getExerciseResultsByUser(
1011
                            api_get_user_id(),
1012
                            $initialData['exercise_id'],
1013
                            $course_info['real_id'],
1014
                            $session_id
1015
                        );
1016
                        if (empty($results)) {
1017
                            api_not_allowed($print_headers);
1018
1019
                            return false;
1020
                        }
1021
                    }
1022
                }*/
1023
            }
1024
        }
1025
    }
1026
1027
    api_block_inactive_user();
1028
1029
    return true;
1030
}
1031
1032
/**
1033
 * Function used to protect an admin script.
1034
 *
1035
 * The function blocks access when the user has no platform admin rights
1036
 * with an error message printed on default output
1037
 *
1038
 * @param bool Whether to allow session admins as well
1039
 * @param bool Whether to allow HR directors as well
1040
 * @param string An optional message (already passed through get_lang)
1041
 *
1042
 * @return bool True if user is allowed, false otherwise.
1043
 *              The function also outputs an error message in case not allowed
1044
 *
1045
 * @author Roan Embrechts (original author)
1046
 */
1047
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1048
{
1049
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1050
        api_not_allowed(true, $message);
1051
1052
        return false;
1053
    }
1054
    api_block_inactive_user();
1055
1056
    return true;
1057
}
1058
1059
/**
1060
 * Blocks inactive users with a currently active session from accessing more pages "live".
1061
 *
1062
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1063
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1064
 */
1065
function api_block_inactive_user()
1066
{
1067
    $data = true;
1068
    if (1 != api_get_configuration_value('security_block_inactive_users_immediately')) {
1069
        return $data;
1070
    }
1071
1072
    $userId = api_get_user_id();
1073
    $homeUrl = api_get_path(WEB_PATH);
1074
    if (0 == $userId) {
1075
        return $data;
1076
    }
1077
1078
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1079
            WHERE id = $userId";
1080
1081
    $result = Database::query($sql);
1082
    if (Database::num_rows($result) > 0) {
1083
        $result_array = Database::fetch_array($result);
1084
        $data = (bool) $result_array['active'];
1085
    }
1086
    if (false == $data) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1087
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1088
        $tpl->assign('hide_login_link', 1);
1089
1090
        //api_not_allowed(true, get_lang('AccountInactive'));
1091
        // we were not in a course, return to home page
1092
        $msg = Display::return_message(
1093
            get_lang('AccountInactive'),
1094
            'error',
1095
            false
1096
        );
1097
1098
        $msg .= '<p class="text-center">
1099
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1100
1101
        $tpl->assign('content', $msg);
1102
        $tpl->display_one_col_template();
1103
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1104
    }
1105
1106
    return $data;
1107
}
1108
1109
/**
1110
 * Function used to protect a teacher script.
1111
 * The function blocks access when the user has no teacher rights.
1112
 *
1113
 * @return bool True if the current user can access the script, false otherwise
1114
 *
1115
 * @author Yoselyn Castillo
1116
 */
1117
function api_protect_teacher_script()
1118
{
1119
    if (!api_is_allowed_to_edit()) {
1120
        api_not_allowed(true);
1121
1122
        return false;
1123
    }
1124
1125
    return true;
1126
}
1127
1128
/**
1129
 * Function used to prevent anonymous users from accessing a script.
1130
 *
1131
 * @param bool $printHeaders
1132
 *
1133
 * @return bool
1134
 */
1135
function api_block_anonymous_users($printHeaders = true)
1136
{
1137
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
1138
1139
    if (false === $isAuth) {
1140
        api_not_allowed($printHeaders);
1141
1142
        return false;
1143
    }
1144
1145
    api_block_inactive_user();
1146
1147
    return true;
1148
}
1149
1150
/**
1151
 * Returns a rough evaluation of the browser's name and version based on very
1152
 * simple regexp.
1153
 *
1154
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1155
 */
1156
function api_get_navigator()
1157
{
1158
    $navigator = 'Unknown';
1159
    $version = 0;
1160
1161
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1162
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1163
    }
1164
1165
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1166
        $navigator = 'Opera';
1167
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1168
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1169
        $navigator = 'Edge';
1170
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1171
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1172
        $navigator = 'Internet Explorer';
1173
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1174
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1175
        $navigator = 'Chrome';
1176
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1177
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1178
        $navigator = 'Safari';
1179
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1180
            // If this Safari does have the "Version/" string in its user agent
1181
            // then use that as a version indicator rather than what's after
1182
            // "Safari/" which is rather a "build number" or something
1183
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1184
        } else {
1185
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1186
        }
1187
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1188
        $navigator = 'Firefox';
1189
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1190
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1191
        $navigator = 'Netscape';
1192
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1193
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1194
        } else {
1195
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1196
        }
1197
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1198
        $navigator = 'Konqueror';
1199
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1200
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1201
        $navigator = 'AppleWebKit';
1202
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1203
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1204
        $navigator = 'Mozilla';
1205
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1206
    }
1207
1208
    // Now cut extra stuff around (mostly *after*) the version number
1209
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1210
1211
    if (false === strpos($version, '.')) {
1212
        $version = number_format(doubleval($version), 1);
1213
    }
1214
1215
    return ['name' => $navigator, 'version' => $version];
1216
}
1217
1218
/**
1219
 * This function returns the id of the user which is stored in the $_user array.
1220
 *
1221
 * example: The function can be used to check if a user is logged in
1222
 *          if (api_get_user_id())
1223
 *
1224
 * @return int the id of the current user, 0 if is empty
1225
 */
1226
function api_get_user_id()
1227
{
1228
    $userInfo = Session::read('_user');
1229
    if ($userInfo && isset($userInfo['user_id'])) {
1230
        return (int) $userInfo['user_id'];
1231
    }
1232
1233
    return 0;
1234
}
1235
1236
/**
1237
 * Formats user information into a standard array
1238
 * This function should be only used inside api_get_user_info().
1239
 *
1240
 * @param array Non-standard user array
0 ignored issues
show
Documentation Bug introduced by
The doc comment Non-standard at position 0 could not be parsed: Unknown type name 'Non-standard' at position 0 in Non-standard.
Loading history...
1241
 * @param bool $add_password
1242
 * @param bool $loadAvatars  turn off to improve performance
1243
 *
1244
 * @return array Standard user array
1245
 */
1246
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1247
{
1248
    $result = [];
1249
1250
    if (!isset($user['id'])) {
1251
        return [];
1252
    }
1253
1254
    $result['firstname'] = null;
1255
    $result['lastname'] = null;
1256
1257
    if (isset($user['firstname']) && isset($user['lastname'])) {
1258
        // with only lowercase
1259
        $result['firstname'] = $user['firstname'];
1260
        $result['lastname'] = $user['lastname'];
1261
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1262
        // with uppercase letters
1263
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1264
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1265
    }
1266
1267
    if (isset($user['email'])) {
1268
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1269
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1270
    } else {
1271
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1272
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1273
    }
1274
1275
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1276
    $result['complete_name_with_username'] = $result['complete_name'];
1277
1278
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1279
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1280
    }
1281
1282
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1283
    if (!empty($user['email'])) {
1284
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1285
        if ($showEmail) {
1286
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1287
        }
1288
    } else {
1289
        $result['complete_name_with_email'] = $result['complete_name'];
1290
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1291
    }
1292
1293
    // Kept for historical reasons
1294
    $result['firstName'] = $result['firstname'];
1295
    $result['lastName'] = $result['lastname'];
1296
1297
    $attributes = [
1298
        'phone',
1299
        'address',
1300
        'picture_uri',
1301
        'official_code',
1302
        'status',
1303
        'active',
1304
        'auth_source',
1305
        'username',
1306
        'theme',
1307
        'language',
1308
        'creator_id',
1309
        'registration_date',
1310
        'hr_dept_id',
1311
        'expiration_date',
1312
        'last_login',
1313
        'user_is_online',
1314
    ];
1315
1316
    if ('true' === api_get_setting('extended_profile')) {
1317
        $attributes[] = 'competences';
1318
        $attributes[] = 'diplomas';
1319
        $attributes[] = 'teach';
1320
        $attributes[] = 'openarea';
1321
    }
1322
1323
    foreach ($attributes as $attribute) {
1324
        $result[$attribute] = $user[$attribute] ?? null;
1325
    }
1326
1327
    $user_id = (int) $user['id'];
1328
    // Maintain the user_id index for backwards compatibility
1329
    $result['user_id'] = $result['id'] = $user_id;
1330
1331
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1332
    $result['has_certificates'] = 0;
1333
    if (!empty($hasCertificates)) {
1334
        $result['has_certificates'] = 1;
1335
    }
1336
1337
    $result['icon_status'] = '';
1338
    $result['icon_status_medium'] = '';
1339
    $result['is_admin'] = UserManager::is_admin($user_id);
1340
1341
    // Getting user avatar.
1342
    if ($loadAvatars) {
1343
        $result['avatar'] = '';
1344
        $result['avatar_no_query'] = '';
1345
        $result['avatar_small'] = '';
1346
        $result['avatar_medium'] = '';
1347
        $urlImg = api_get_path(WEB_IMG_PATH);
1348
        $iconStatus = '';
1349
        $iconStatusMedium = '';
1350
        $label = '';
1351
        switch ($result['status']) {
1352
            case STUDENT:
1353
                if ($result['has_certificates']) {
1354
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1355
                    $label = get_lang('Graduated');
1356
                } else {
1357
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1358
                    $label = get_lang('Student');
1359
                }
1360
                break;
1361
            case COURSEMANAGER:
1362
                if ($result['is_admin']) {
1363
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1364
                    $label = get_lang('Admin');
1365
                } else {
1366
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1367
                    $label = get_lang('Teacher');
1368
                }
1369
                break;
1370
            case STUDENT_BOSS:
1371
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1372
                $label = get_lang('StudentBoss');
1373
                break;
1374
        }
1375
1376
        if (!empty($iconStatus)) {
1377
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1378
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1379
        }
1380
1381
        $result['icon_status'] = $iconStatus;
1382
        $result['icon_status_label'] = $label;
1383
        $result['icon_status_medium'] = $iconStatusMedium;
1384
    }
1385
1386
    if (isset($user['user_is_online'])) {
1387
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1388
    }
1389
    if (isset($user['user_is_online_in_chat'])) {
1390
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1391
    }
1392
1393
    if ($add_password) {
1394
        $result['password'] = $user['password'];
1395
    }
1396
1397
    if (isset($result['profile_completed'])) {
1398
        $result['profile_completed'] = $user['profile_completed'];
1399
    }
1400
1401
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1402
1403
    // Send message link
1404
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1405
    $result['complete_name_with_message_link'] = Display::url(
1406
        $result['complete_name_with_username'],
1407
        $sendMessage,
1408
        ['class' => 'ajax']
1409
    );
1410
1411
    if (isset($user['extra'])) {
1412
        $result['extra'] = $user['extra'];
1413
    }
1414
1415
    return $result;
1416
}
1417
1418
/**
1419
 * Finds all the information about a user.
1420
 * If no parameter is passed you find all the information about the current user.
1421
 *
1422
 * @param int  $user_id
1423
 * @param bool $checkIfUserOnline
1424
 * @param bool $showPassword
1425
 * @param bool $loadExtraData
1426
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1427
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1428
 * @param bool $updateCache              update apc cache if exists
1429
 *
1430
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1431
 *
1432
 * @author Patrick Cool <[email protected]>
1433
 * @author Julio Montoya
1434
 *
1435
 * @version 21 September 2004
1436
 */
1437
function api_get_user_info(
1438
    $user_id = 0,
1439
    $checkIfUserOnline = false,
1440
    $showPassword = false,
1441
    $loadExtraData = false,
1442
    $loadOnlyVisibleExtraData = false,
1443
    $loadAvatars = true,
1444
    $updateCache = false
1445
) {
1446
    // Make sure user_id is safe
1447
    $user_id = (int) $user_id;
1448
    $user = false;
1449
    if (empty($user_id)) {
1450
        $userFromSession = Session::read('_user');
1451
        if (isset($userFromSession) && !empty($userFromSession)) {
1452
            return $userFromSession;
1453
            /*
1454
            return _api_format_user(
1455
                $userFromSession,
1456
                $showPassword,
1457
                $loadAvatars
1458
            );*/
1459
        }
1460
1461
        return false;
1462
    }
1463
1464
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1465
            WHERE id = $user_id";
1466
    $result = Database::query($sql);
1467
    if (Database::num_rows($result) > 0) {
1468
        $result_array = Database::fetch_array($result);
1469
        $result_array['user_is_online_in_chat'] = 0;
1470
        if ($checkIfUserOnline) {
1471
            $use_status_in_platform = user_is_online($user_id);
1472
            $result_array['user_is_online'] = $use_status_in_platform;
1473
            $user_online_in_chat = 0;
1474
            if ($use_status_in_platform) {
1475
                $user_status = UserManager::get_extra_user_data_by_field(
1476
                    $user_id,
1477
                    'user_chat_status',
1478
                    false,
1479
                    true
1480
                );
1481
                if (1 == (int) $user_status['user_chat_status']) {
1482
                    $user_online_in_chat = 1;
1483
                }
1484
            }
1485
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1486
        }
1487
1488
        if ($loadExtraData) {
1489
            $fieldValue = new ExtraFieldValue('user');
1490
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1491
                $user_id,
1492
                $loadOnlyVisibleExtraData
1493
            );
1494
        }
1495
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1496
    }
1497
1498
    return $user;
1499
}
1500
1501
function api_get_user_info_from_entity(
1502
    User $user,
1503
    $checkIfUserOnline = false,
1504
    $showPassword = false,
1505
    $loadExtraData = false,
1506
    $loadOnlyVisibleExtraData = false,
1507
    $loadAvatars = true,
1508
    $loadCertificate = false
1509
) {
1510
    if (!$user instanceof UserInterface) {
1511
        return false;
1512
    }
1513
1514
    // Make sure user_id is safe
1515
    $user_id = (int) $user->getId();
1516
1517
    if (empty($user_id)) {
1518
        $userFromSession = Session::read('_user');
1519
1520
        if (isset($userFromSession) && !empty($userFromSession)) {
1521
            return $userFromSession;
1522
        }
1523
1524
        return false;
1525
    }
1526
1527
    $result = [];
1528
    $result['user_is_online_in_chat'] = 0;
1529
    if ($checkIfUserOnline) {
1530
        $use_status_in_platform = user_is_online($user_id);
1531
        $result['user_is_online'] = $use_status_in_platform;
1532
        $user_online_in_chat = 0;
1533
        if ($use_status_in_platform) {
1534
            $user_status = UserManager::get_extra_user_data_by_field(
1535
                $user_id,
1536
                'user_chat_status',
1537
                false,
1538
                true
1539
            );
1540
            if (1 == (int) $user_status['user_chat_status']) {
1541
                $user_online_in_chat = 1;
1542
            }
1543
        }
1544
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1545
    }
1546
1547
    if ($loadExtraData) {
1548
        $fieldValue = new ExtraFieldValue('user');
1549
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1550
            $user_id,
1551
            $loadOnlyVisibleExtraData
1552
        );
1553
    }
1554
1555
    $result['username'] = $user->getUsername();
1556
    $result['status'] = $user->getStatus();
1557
    $result['firstname'] = $user->getFirstname();
1558
    $result['lastname'] = $user->getLastname();
1559
    $result['email'] = $result['mail'] = $user->getEmail();
1560
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1561
    $result['complete_name_with_username'] = $result['complete_name'];
1562
1563
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1564
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1565
    }
1566
1567
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1568
    if (!empty($result['email'])) {
1569
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1570
        if ($showEmail) {
1571
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1572
        }
1573
    } else {
1574
        $result['complete_name_with_email'] = $result['complete_name'];
1575
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1576
    }
1577
1578
    // Kept for historical reasons
1579
    $result['firstName'] = $result['firstname'];
1580
    $result['lastName'] = $result['lastname'];
1581
1582
    $attributes = [
1583
        'picture_uri',
1584
        'last_login',
1585
        'user_is_online',
1586
    ];
1587
1588
    $result['phone'] = $user->getPhone();
1589
    $result['address'] = $user->getAddress();
1590
    $result['official_code'] = $user->getOfficialCode();
1591
    $result['active'] = $user->getActive();
1592
    $result['auth_source'] = $user->getAuthSource();
1593
    $result['language'] = $user->getLocale();
1594
    $result['creator_id'] = $user->getCreatorId();
1595
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1596
    $result['hr_dept_id'] = $user->getHrDeptId();
1597
    $result['expiration_date'] = '';
1598
    if ($user->getExpirationDate()) {
1599
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1600
    }
1601
1602
    $result['last_login'] = null;
1603
    if ($user->getLastLogin()) {
1604
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1605
    }
1606
1607
    $result['competences'] = $user->getCompetences();
1608
    $result['diplomas'] = $user->getDiplomas();
1609
    $result['teach'] = $user->getTeach();
1610
    $result['openarea'] = $user->getOpenarea();
1611
    $user_id = (int) $user->getId();
1612
1613
    // Maintain the user_id index for backwards compatibility
1614
    $result['user_id'] = $result['id'] = $user_id;
1615
1616
    if ($loadCertificate) {
1617
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1618
        $result['has_certificates'] = 0;
1619
        if (!empty($hasCertificates)) {
1620
            $result['has_certificates'] = 1;
1621
        }
1622
    }
1623
1624
    $result['icon_status'] = '';
1625
    $result['icon_status_medium'] = '';
1626
    $result['is_admin'] = UserManager::is_admin($user_id);
1627
1628
    // Getting user avatar.
1629
    if ($loadAvatars) {
1630
        $result['avatar'] = '';
1631
        $result['avatar_no_query'] = '';
1632
        $result['avatar_small'] = '';
1633
        $result['avatar_medium'] = '';
1634
        $urlImg = '/';
1635
        $iconStatus = '';
1636
        $iconStatusMedium = '';
1637
1638
        switch ($user->getStatus()) {
1639
            case STUDENT:
1640
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1641
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1642
                } else {
1643
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1644
                }
1645
                break;
1646
            case COURSEMANAGER:
1647
                if ($result['is_admin']) {
1648
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1649
                } else {
1650
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1651
                }
1652
                break;
1653
            case STUDENT_BOSS:
1654
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1655
                break;
1656
        }
1657
1658
        if (!empty($iconStatus)) {
1659
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1660
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1661
        }
1662
1663
        $result['icon_status'] = $iconStatus;
1664
        $result['icon_status_medium'] = $iconStatusMedium;
1665
    }
1666
1667
    if (isset($result['user_is_online'])) {
1668
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1669
    }
1670
    if (isset($result['user_is_online_in_chat'])) {
1671
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1672
    }
1673
1674
    $result['password'] = '';
1675
    if ($showPassword) {
1676
        $result['password'] = $user->getPassword();
1677
    }
1678
1679
    if (isset($result['profile_completed'])) {
1680
        $result['profile_completed'] = $result['profile_completed'];
1681
    }
1682
1683
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1684
1685
    // Send message link
1686
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1687
    $result['complete_name_with_message_link'] = Display::url(
1688
        $result['complete_name_with_username'],
1689
        $sendMessage,
1690
        ['class' => 'ajax']
1691
    );
1692
1693
    if (isset($result['extra'])) {
1694
        $result['extra'] = $result['extra'];
1695
    }
1696
1697
    return $result;
1698
}
1699
1700
function api_get_lp_entity(int $id): ?CLp
1701
{
1702
    return Database::getManager()->getRepository(CLp::class)->find($id);
1703
}
1704
1705
function api_get_user_entity(int $userId = 0): ?User
1706
{
1707
    $userId = $userId ?: api_get_user_id();
1708
    $repo = UserManager::getRepository();
1709
1710
    return $repo->find($userId);
1711
}
1712
1713
function api_get_current_user(): ?User
1714
{
1715
    $isLoggedIn = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_REMEMBERED');
1716
    if (false === $isLoggedIn) {
1717
        return null;
1718
    }
1719
1720
    $token = Container::getTokenStorage()->getToken();
1721
1722
    if (null !== $token) {
1723
        return $token->getUser();
1724
    }
1725
1726
    return null;
1727
}
1728
1729
/**
1730
 * Finds all the information about a user from username instead of user id.
1731
 *
1732
 * @param string $username
1733
 *
1734
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1735
 *
1736
 * @author Yannick Warnier <[email protected]>
1737
 */
1738
function api_get_user_info_from_username($username)
1739
{
1740
    if (empty($username)) {
1741
        return false;
1742
    }
1743
    $username = trim($username);
1744
1745
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1746
            WHERE username='".Database::escape_string($username)."'";
1747
    $result = Database::query($sql);
1748
    if (Database::num_rows($result) > 0) {
1749
        $resultArray = Database::fetch_array($result);
1750
1751
        return _api_format_user($resultArray);
1752
    }
1753
1754
    return false;
1755
}
1756
1757
/**
1758
 * Get first user with an email.
1759
 *
1760
 * @param string $email
1761
 *
1762
 * @return array|bool
1763
 */
1764
function api_get_user_info_from_email($email = '')
1765
{
1766
    if (empty($email)) {
1767
        return false;
1768
    }
1769
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1770
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1771
    $result = Database::query($sql);
1772
    if (Database::num_rows($result) > 0) {
1773
        $resultArray = Database::fetch_array($result);
1774
1775
        return _api_format_user($resultArray);
1776
    }
1777
1778
    return false;
1779
}
1780
1781
/**
1782
 * @return string
1783
 */
1784
function api_get_course_id()
1785
{
1786
    return Session::read('_cid', null);
1787
}
1788
1789
/**
1790
 * Returns the current course id (integer).
1791
 *
1792
 * @param string $code Optional course code
1793
 *
1794
 * @return int
1795
 */
1796
function api_get_course_int_id($code = null)
1797
{
1798
    if (!empty($code)) {
1799
        $code = Database::escape_string($code);
1800
        $row = Database::select(
1801
            'id',
1802
            Database::get_main_table(TABLE_MAIN_COURSE),
1803
            ['where' => ['code = ?' => [$code]]],
1804
            'first'
1805
        );
1806
1807
        if (is_array($row) && isset($row['id'])) {
1808
            return $row['id'];
1809
        } else {
1810
            return false;
1811
        }
1812
    }
1813
1814
    return Session::read('_real_cid', 0);
1815
}
1816
1817
/**
1818
 * Gets a course setting from the current course_setting table. Try always using integer values.
1819
 *
1820
 * @param string       $settingName The name of the setting we want from the table
1821
 * @param Course|array $courseInfo
1822
 * @param bool         $force       force checking the value in the database
1823
 *
1824
 * @return mixed The value of that setting in that table. Return -1 if not found.
1825
 */
1826
function api_get_course_setting($settingName, $courseInfo = null, $force = false)
1827
{
1828
    if (empty($courseInfo)) {
1829
        $courseInfo = api_get_course_info();
1830
    }
1831
1832
    if (empty($courseInfo) || empty($settingName)) {
1833
        return -1;
1834
    }
1835
1836
    if ($courseInfo instanceof Course) {
1837
        $courseId = $courseInfo->getId();
1838
    } else {
1839
        $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1840
    }
1841
1842
    if (empty($courseId)) {
1843
        return -1;
1844
    }
1845
1846
    static $courseSettingInfo = [];
1847
1848
    if ($force) {
1849
        $courseSettingInfo = [];
1850
    }
1851
1852
    if (!isset($courseSettingInfo[$courseId])) {
1853
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
1854
        $settingName = Database::escape_string($settingName);
1855
1856
        $sql = "SELECT variable, value FROM $table
1857
                WHERE c_id = $courseId ";
1858
        $res = Database::query($sql);
1859
        if (Database::num_rows($res) > 0) {
1860
            $result = Database::store_result($res, 'ASSOC');
1861
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
1862
1863
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
1864
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
1865
                if (!is_null($value)) {
1866
                    $result = explode(',', $value);
1867
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
1868
                }
1869
            }
1870
        }
1871
    }
1872
1873
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
1874
        return $courseSettingInfo[$courseId][$settingName];
1875
    }
1876
1877
    return -1;
1878
}
1879
1880
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
1881
{
1882
    $value = api_get_course_setting($settingName, $courseInfo, true);
1883
1884
    if (-1 === $value) {
1885
        // Check global settings
1886
        $value = api_get_plugin_setting($plugin, $settingName);
1887
        if ('true' === $value) {
1888
            return 1;
1889
        }
1890
        if ('false' === $value) {
1891
            return 0;
1892
        }
1893
        if (null === $value) {
1894
            return -1;
1895
        }
1896
    }
1897
1898
    return $value;
1899
}
1900
1901
/**
1902
 * Gets an anonymous user ID.
1903
 *
1904
 * For some tools that need tracking, like the learnpath tool, it is necessary
1905
 * to have a usable user-id to enable some kind of tracking, even if not
1906
 * perfect. An anonymous ID is taken from the users table by looking for a
1907
 * status of "6" (anonymous).
1908
 *
1909
 * @return int User ID of the anonymous user, or O if no anonymous user found
1910
 */
1911
function api_get_anonymous_id()
1912
{
1913
    // Find if another anon is connected now
1914
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1915
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1916
    $ip = Database::escape_string(api_get_real_ip());
1917
    $max = (int) api_get_configuration_value('max_anonymous_users');
1918
    if ($max >= 2) {
1919
        $sql = "SELECT * FROM $table as TEL
1920
                JOIN $tableU as U
1921
                ON U.id = TEL.login_user_id
1922
                WHERE TEL.user_ip = '$ip'
1923
                    AND U.status = ".ANONYMOUS."
1924
                    AND U.id != 2 ";
1925
1926
        $result = Database::query($sql);
1927
        if (empty(Database::num_rows($result))) {
1928
            $login = uniqid('anon_');
1929
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1930
            if (count($anonList) >= $max) {
1931
                foreach ($anonList as $userToDelete) {
1932
                    UserManager::delete_user($userToDelete['user_id']);
1933
                    break;
1934
                }
1935
            }
1936
1937
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...lhost', $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
1938
                $login,
1939
                'anon',
1940
                ANONYMOUS,
1941
                ' anonymous@localhost',
1942
                $login,
1943
                $login
1944
            );
1945
        } else {
1946
            $row = Database::fetch_array($result, 'ASSOC');
1947
1948
            return $row['id'];
1949
        }
1950
    }
1951
1952
    $table = Database::get_main_table(TABLE_MAIN_USER);
1953
    $sql = "SELECT id
1954
            FROM $table
1955
            WHERE status = ".ANONYMOUS." ";
1956
    $res = Database::query($sql);
1957
    if (Database::num_rows($res) > 0) {
1958
        $row = Database::fetch_array($res, 'ASSOC');
1959
1960
        return $row['id'];
1961
    }
1962
1963
    // No anonymous user was found.
1964
    return 0;
1965
}
1966
1967
/**
1968
 * @param int $courseId
1969
 * @param int $sessionId
1970
 * @param int $groupId
1971
 *
1972
 * @return string
1973
 */
1974
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
1975
{
1976
    $courseId = !empty($courseId) ? (int) $courseId : 0;
1977
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1978
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1979
1980
    $url = 'cid='.$courseId;
1981
    $url .= '&sid='.$sessionId;
1982
    $url .= '&gid='.$groupId;
1983
1984
    return $url;
1985
}
1986
1987
/**
1988
 * Returns the current course url part including session, group, and gradebook params.
1989
 *
1990
 * @param bool   $addSessionId
1991
 * @param bool   $addGroupId
1992
 * @param string $origin
1993
 *
1994
 * @return string Course & session references to add to a URL
1995
 */
1996
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1997
{
1998
    $courseId = api_get_course_int_id();
1999
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2000
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2001
2002
    if ($addSessionId) {
2003
        if (!empty($url)) {
2004
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2005
        }
2006
    }
2007
2008
    if ($addGroupId) {
2009
        if (!empty($url)) {
2010
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2011
        }
2012
    }
2013
2014
    if (!empty($url)) {
2015
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2016
        $url .= '&origin='.$origin;
0 ignored issues
show
Bug introduced by
Are you sure $origin of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2016
        $url .= '&origin='./** @scrutinizer ignore-type */ $origin;
Loading history...
2017
    }
2018
2019
    return $url;
2020
}
2021
2022
/**
2023
 * Get if we visited a gradebook page.
2024
 *
2025
 * @return bool
2026
 */
2027
function api_is_in_gradebook()
2028
{
2029
    return Session::read('in_gradebook', false);
2030
}
2031
2032
/**
2033
 * Set that we are in a page inside a gradebook.
2034
 */
2035
function api_set_in_gradebook()
2036
{
2037
    Session::write('in_gradebook', true);
2038
}
2039
2040
/**
2041
 * Remove gradebook session.
2042
 */
2043
function api_remove_in_gradebook()
2044
{
2045
    Session::erase('in_gradebook');
2046
}
2047
2048
/**
2049
 * Returns the current course info array see api_format_course_array()
2050
 * If the course_code is given, the returned array gives info about that
2051
 * particular course, if none given it gets the course info from the session.
2052
 *
2053
 * @param string $courseCode
2054
 *
2055
 * @return array
2056
 */
2057
function api_get_course_info($courseCode = null)
2058
{
2059
    if (!empty($courseCode)) {
2060
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2061
2062
        return api_format_course_array($course);
2063
    }
2064
2065
    $course = Session::read('_course');
2066
    if ('-1' == $course) {
2067
        $course = [];
2068
    }
2069
2070
    return $course;
2071
}
2072
2073
/**
2074
 * @param int $courseId
2075
 */
2076
function api_get_course_entity($courseId = 0): ?Course
2077
{
2078
    if (empty($courseId)) {
2079
        $courseId = api_get_course_int_id();
2080
    }
2081
2082
    if (empty($courseId)) {
2083
        return null;
2084
    }
2085
2086
    return Container::getCourseRepository()->find($courseId);
2087
}
2088
2089
/**
2090
 * @param int $id
2091
 */
2092
function api_get_session_entity($id = 0): ?SessionEntity
2093
{
2094
    if (empty($id)) {
2095
        $id = api_get_session_id();
2096
    }
2097
2098
    if (empty($id)) {
2099
        return null;
2100
    }
2101
2102
    return Container::getSessionRepository()->find($id);
2103
}
2104
2105
/**
2106
 * @param int $id
2107
 */
2108
function api_get_group_entity($id = 0): ?CGroup
2109
{
2110
    if (empty($id)) {
2111
        $id = api_get_group_id();
2112
    }
2113
2114
    return Container::getGroupRepository()->find($id);
2115
}
2116
2117
/**
2118
 * @param int $id
2119
 */
2120
function api_get_url_entity($id = 0): ?AccessUrl
2121
{
2122
    if (empty($id)) {
2123
        $id = api_get_current_access_url_id();
2124
    }
2125
2126
    return Container::getAccessUrlRepository()->find($id);
2127
}
2128
2129
/**
2130
 * Returns the current course info array.
2131
2132
 * Now if the course_code is given, the returned array gives info about that
2133
 * particular course, not specially the current one.
2134
 *
2135
 * @param int $id Numeric ID of the course
2136
 *
2137
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2138
 */
2139
function api_get_course_info_by_id($id = 0)
2140
{
2141
    $id = (int) $id;
2142
    if (empty($id)) {
2143
        $course = Session::read('_course', []);
2144
2145
        return $course;
2146
    }
2147
2148
    $course = Container::getCourseRepository()->find($id);
2149
    if (empty($course)) {
2150
        return [];
2151
    }
2152
2153
    return api_format_course_array($course);
2154
}
2155
2156
/**
2157
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2158
 * to switch from 'code' to 'id' in the array.
2159
 *
2160
 * @return array
2161
 *
2162
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2163
 */
2164
function api_format_course_array(Course $course = null)
2165
{
2166
    if (empty($course)) {
2167
        return [];
2168
    }
2169
2170
    $courseData = [];
2171
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2172
2173
    // Added
2174
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2175
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2176
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2177
    //$courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2178
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2179
    $courseData['titular'] = $course->getTutorName();
2180
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2181
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2182
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2183
2184
    $courseData['visibility'] = $course->getVisibility();
2185
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2186
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2187
    $courseData['activate_legal'] = $course->getActivateLegal();
2188
    $courseData['legal'] = $course->getLegal();
2189
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2190
2191
    $coursePath = '/course/';
2192
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2193
2194
    // Course password
2195
    $courseData['registration_code'] = $course->getRegistrationCode();
2196
    $courseData['disk_quota'] = $course->getDiskQuota();
2197
    $courseData['course_public_url'] = $webCourseHome;
2198
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2199
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2200
    $courseData['entity'] = $course;
2201
2202
    $image = Display::return_icon(
2203
        'course.png',
2204
        null,
2205
        null,
2206
        ICON_SIZE_BIG,
2207
        null,
2208
        true,
2209
        false
2210
    );
2211
2212
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2213
    if (!empty($illustration)) {
2214
        $image = $illustration;
2215
    }
2216
2217
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2218
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2219
2220
    return $courseData;
2221
}
2222
2223
/**
2224
 * Returns a difficult to guess password.
2225
 *
2226
 * @param int $length the length of the password
2227
 *
2228
 * @return string the generated password
2229
 */
2230
function api_generate_password($length = 8)
2231
{
2232
    if ($length < 2) {
2233
        $length = 2;
2234
    }
2235
2236
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2237
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2238
    $minNumbers = 2;
2239
    $length = $length - $minNumbers;
2240
    $minLowerCase = round($length / 2);
2241
    $minUpperCase = $length - $minLowerCase;
2242
2243
    $password = '';
2244
    $passwordRequirements = api_get_configuration_value('password_requirements');
2245
2246
    $factory = new RandomLib\Factory();
2247
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2248
2249
    if (!empty($passwordRequirements)) {
2250
        $length = $passwordRequirements['min']['length'];
2251
        $minNumbers = $passwordRequirements['min']['numeric'];
2252
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2253
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2254
2255
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2256
        // Add the rest to fill the length requirement
2257
        if ($rest > 0) {
2258
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2259
        }
2260
    }
2261
2262
    // Min digits default 2
2263
    for ($i = 0; $i < $minNumbers; $i++) {
2264
        $password .= $generator->generateInt(2, 9);
2265
    }
2266
2267
    // Min lowercase
2268
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2269
2270
    // Min uppercase
2271
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2272
    $password = str_shuffle($password);
2273
2274
    return $password;
2275
}
2276
2277
/**
2278
 * Checks a password to see wether it is OK to use.
2279
 *
2280
 * @param string $password
2281
 *
2282
 * @return bool if the password is acceptable, false otherwise
2283
 *              Notes about what a password "OK to use" is:
2284
 *              1. The password should be at least 5 characters long.
2285
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2286
 *              3. The password should contain at least 3 letters.
2287
 *              4. It should contain at least 2 digits.
2288
 *              Settings will change if the configuration value is set: password_requirements
2289
 */
2290
function api_check_password($password)
2291
{
2292
    $passwordRequirements = Security::getPasswordRequirements();
2293
2294
    $minLength = $passwordRequirements['min']['length'];
2295
    $minNumbers = $passwordRequirements['min']['numeric'];
2296
    // Optional
2297
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2298
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2299
2300
    $minLetters = $minLowerCase + $minUpperCase;
2301
    $passwordLength = api_strlen($password);
2302
2303
    $conditions = [
2304
        'min_length' => $passwordLength >= $minLength,
2305
    ];
2306
2307
    $digits = 0;
2308
    $lowerCase = 0;
2309
    $upperCase = 0;
2310
2311
    for ($i = 0; $i < $passwordLength; $i++) {
2312
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2313
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2314
            $upperCase++;
2315
        }
2316
2317
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2318
            $lowerCase++;
2319
        }
2320
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2321
            $digits++;
2322
        }
2323
    }
2324
2325
    // Min number of digits
2326
    $conditions['min_numeric'] = $digits >= $minNumbers;
2327
2328
    if (!empty($minUpperCase)) {
2329
        // Uppercase
2330
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2331
    }
2332
2333
    if (!empty($minLowerCase)) {
2334
        // Lowercase
2335
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2336
    }
2337
2338
    // Min letters
2339
    $letters = $upperCase + $lowerCase;
2340
    $conditions['min_letters'] = $letters >= $minLetters;
2341
2342
    $isPasswordOk = true;
2343
    foreach ($conditions as $condition) {
2344
        if (false === $condition) {
2345
            $isPasswordOk = false;
2346
            break;
2347
        }
2348
    }
2349
2350
    if (false === $isPasswordOk) {
2351
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2352
        $output .= Security::getPasswordRequirementsToString($conditions);
2353
2354
        Display::addFlash(Display::return_message($output, 'warning', false));
2355
    }
2356
2357
    return $isPasswordOk;
2358
}
2359
2360
/**
2361
 * Returns the status string corresponding to the status code.
2362
 *
2363
 * @author Noel Dieschburg
2364
 *
2365
 * @param the int status code
2366
 *
2367
 * @return string
2368
 */
2369
function get_status_from_code($status_code)
2370
{
2371
    switch ($status_code) {
2372
        case STUDENT:
2373
            return get_lang('Student');
2374
        case COURSEMANAGER:
2375
            return get_lang('Teacher');
2376
        case SESSIONADMIN:
2377
            return get_lang('SessionsAdmin');
2378
        case DRH:
2379
            return get_lang('Drh');
2380
        case ANONYMOUS:
2381
            return get_lang('Anonymous');
2382
        case PLATFORM_ADMIN:
2383
            return get_lang('Administrator');
2384
        case SESSION_COURSE_COACH:
2385
            return get_lang('SessionCourseCoach');
2386
        case SESSION_GENERAL_COACH:
2387
            return get_lang('SessionGeneralCoach');
2388
        case COURSE_TUTOR:
2389
            return get_lang('CourseAssistant');
2390
        case STUDENT_BOSS:
2391
            return get_lang('StudentBoss');
2392
        case INVITEE:
2393
            return get_lang('Invitee');
2394
    }
2395
}
2396
2397
/**
2398
 * Gets the current Chamilo (not PHP/cookie) session ID.
2399
 *
2400
 * @return int O if no active session, the session ID otherwise
2401
 */
2402
function api_get_session_id()
2403
{
2404
    return (int) Session::read('sid', 0);
2405
}
2406
2407
/**
2408
 * Gets the current Chamilo (not social network) group ID.
2409
 *
2410
 * @return int O if no active session, the session ID otherwise
2411
 */
2412
function api_get_group_id()
2413
{
2414
    return Session::read('gid', 0);
2415
}
2416
2417
/**
2418
 * Gets the current or given session name.
2419
 *
2420
 * @param   int     Session ID (optional)
2421
 *
2422
 * @return string The session name, or null if not found
2423
 */
2424
function api_get_session_name($session_id = 0)
2425
{
2426
    if (empty($session_id)) {
2427
        $session_id = api_get_session_id();
2428
        if (empty($session_id)) {
2429
            return null;
2430
        }
2431
    }
2432
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2433
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2434
    $r = Database::query($s);
2435
    $c = Database::num_rows($r);
2436
    if ($c > 0) {
2437
        //technically, there can be only one, but anyway we take the first
2438
        $rec = Database::fetch_array($r);
2439
2440
        return $rec['name'];
2441
    }
2442
2443
    return null;
2444
}
2445
2446
/**
2447
 * Gets the session info by id.
2448
 *
2449
 * @param int $id Session ID
2450
 *
2451
 * @return array information of the session
2452
 */
2453
function api_get_session_info($id)
2454
{
2455
    return SessionManager::fetch($id);
2456
}
2457
2458
/**
2459
 * Gets the session visibility by session id.
2460
 *
2461
 * @param int  $session_id
2462
 * @param int  $courseId
2463
 * @param bool $ignore_visibility_for_admins
2464
 *
2465
 * @return int
2466
 *             0 = session still available,
2467
 *             SESSION_VISIBLE_READ_ONLY = 1,
2468
 *             SESSION_VISIBLE = 2,
2469
 *             SESSION_INVISIBLE = 3
2470
 */
2471
function api_get_session_visibility(
2472
    $session_id,
2473
    $courseId = null,
2474
    $ignore_visibility_for_admins = true,
2475
    $userId = 0
2476
) {
2477
    if (api_is_platform_admin()) {
2478
        if ($ignore_visibility_for_admins) {
2479
            return SESSION_AVAILABLE;
2480
        }
2481
    }
2482
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2483
2484
    $now = time();
2485
    if (empty($session_id)) {
2486
        return 0; // Means that the session is still available.
2487
    }
2488
2489
    $session_id = (int) $session_id;
2490
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2491
2492
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2493
2494
    if (Database::num_rows($result) <= 0) {
2495
        return SESSION_INVISIBLE;
2496
    }
2497
2498
    $row = Database::fetch_array($result, 'ASSOC');
2499
    $visibility = $row['visibility'];
2500
2501
    // I don't care the session visibility.
2502
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2503
        // Session duration per student.
2504
        if (isset($row['duration']) && !empty($row['duration'])) {
2505
            $duration = $row['duration'] * 24 * 60 * 60;
2506
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2507
2508
            // If there is a session duration but there is no previous
2509
            // access by the user, then the session is still available
2510
            if (0 == count($courseAccess)) {
2511
                return SESSION_AVAILABLE;
2512
            }
2513
2514
            $currentTime = time();
2515
            $firstAccess = isset($courseAccess['login_course_date'])
2516
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2517
                : 0;
2518
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2519
            $userDuration = isset($userDurationData['duration'])
2520
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2521
                : 0;
2522
2523
            $totalDuration = $firstAccess + $duration + $userDuration;
2524
2525
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2526
        }
2527
2528
        return SESSION_AVAILABLE;
2529
    }
2530
2531
    // If start date was set.
2532
    if (!empty($row['access_start_date'])) {
2533
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2534
    }
2535
2536
    // If the end date was set.
2537
    if (!empty($row['access_end_date'])) {
2538
        // Only if date_start said that it was ok
2539
        if (SESSION_AVAILABLE === $visibility) {
2540
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2541
                ? SESSION_AVAILABLE // Date still available
2542
                : $row['visibility']; // Session ends
2543
        }
2544
    }
2545
2546
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2547
    $isCoach = api_is_coach($session_id, $courseId);
2548
2549
    if ($isCoach) {
2550
        // Test start date.
2551
        if (!empty($row['coach_access_start_date'])) {
2552
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2553
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2554
        }
2555
2556
        // Test end date.
2557
        if (!empty($row['coach_access_end_date'])) {
2558
            if (SESSION_AVAILABLE === $visibility) {
2559
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2560
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2561
            }
2562
        }
2563
    }
2564
2565
    return $visibility;
2566
}
2567
2568
/**
2569
 * This function returns a (star) session icon if the session is not null and
2570
 * the user is not a student.
2571
 *
2572
 * @param int $sessionId
2573
 * @param int $statusId  User status id - if 5 (student), will return empty
2574
 *
2575
 * @return string Session icon
2576
 */
2577
function api_get_session_image($sessionId, $statusId)
2578
{
2579
    $sessionId = (int) $sessionId;
2580
    $image = '';
2581
    if (STUDENT != $statusId) {
2582
        // Check whether is not a student
2583
        if ($sessionId > 0) {
2584
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2585
                'star.png',
2586
                get_lang('Session-specific resource'),
2587
                ['align' => 'absmiddle'],
2588
                ICON_SIZE_SMALL
2589
            );
2590
        }
2591
    }
2592
2593
    return $image;
2594
}
2595
2596
/**
2597
 * This function add an additional condition according to the session of the course.
2598
 *
2599
 * @param int    $session_id        session id
2600
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2601
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2602
 *                                  false for strict session condition
2603
 * @param string $session_field
2604
 *
2605
 * @return string condition of the session
2606
 */
2607
function api_get_session_condition(
2608
    $session_id,
2609
    $and = true,
2610
    $with_base_content = false,
2611
    $session_field = 'session_id'
2612
) {
2613
    $session_id = (int) $session_id;
2614
2615
    if (empty($session_field)) {
2616
        $session_field = 'session_id';
2617
    }
2618
    // Condition to show resources by session
2619
    $condition_add = $and ? ' AND ' : ' WHERE ';
2620
2621
    if ($with_base_content) {
2622
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2623
    } else {
2624
        if (empty($session_id)) {
2625
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2626
        } else {
2627
            $condition_session = $condition_add." $session_field = $session_id ";
2628
        }
2629
    }
2630
2631
    return $condition_session;
2632
}
2633
2634
/**
2635
 * Returns the value of a setting from the web-adjustable admin config settings.
2636
 *
2637
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2638
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2639
 * instead of
2640
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2641
 *
2642
 * @param string $variable The variable name
2643
 *
2644
 * @return string|array
2645
 */
2646
function api_get_setting($variable)
2647
{
2648
    $settingsManager = Container::getSettingsManager();
2649
    if (empty($settingsManager)) {
2650
        return '';
2651
    }
2652
    $variable = trim($variable);
2653
2654
    switch ($variable) {
2655
        case 'server_type':
2656
            $test = ['dev', 'test'];
2657
            $environment = Container::getEnvironment();
2658
            if (in_array($environment, $test)) {
2659
                return 'test';
2660
            }
2661
2662
            return 'prod';
2663
        case 'stylesheets':
2664
            $variable = 'platform.theme';
2665
        // deprecated settings
2666
        // no break
2667
        case 'openid_authentication':
2668
        case 'service_ppt2lp':
2669
        case 'formLogin_hide_unhide_label':
2670
            return false;
2671
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2672
        case 'tool_visible_by_default_at_creation':
2673
            $values = $settingsManager->getSetting($variable);
2674
            $newResult = [];
2675
            foreach ($values as $parameter) {
2676
                $newResult[$parameter] = 'true';
2677
            }
2678
2679
            return $newResult;
2680
            break;
2681
        default:
2682
            return $settingsManager->getSetting($variable);
2683
            break;
2684
    }
2685
}
2686
2687
/**
2688
 * @param string $variable
2689
 * @param string $option
2690
 *
2691
 * @return bool
2692
 */
2693
function api_get_setting_in_list($variable, $option)
2694
{
2695
    $value = api_get_setting($variable);
2696
2697
    return in_array($option, $value);
2698
}
2699
2700
/**
2701
 * @param string $plugin
2702
 * @param string $variable
2703
 *
2704
 * @return string
2705
 */
2706
function api_get_plugin_setting($plugin, $variable)
2707
{
2708
    $variableName = $plugin.'_'.$variable;
2709
    //$result = api_get_setting($variableName);
2710
    $params = [
2711
        'category = ? AND subkey = ? AND variable = ?' => [
2712
            'Plugins',
2713
            $plugin,
2714
            $variableName,
2715
        ],
2716
    ];
2717
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2718
    $result = Database::select(
2719
        'selected_value',
2720
        $table,
2721
        ['where' => $params],
2722
        'one'
2723
    );
2724
    if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2725
        $value = $result['selected_value'];
2726
        $serializedValue = @unserialize($result['selected_value'], []);
2727
        if (false !== $serializedValue) {
2728
            $value = $serializedValue;
2729
        }
2730
2731
        return $value;
2732
    }
2733
2734
    return null;
2735
    /// Old code
2736
2737
    $variableName = $plugin.'_'.$variable;
0 ignored issues
show
Unused Code introduced by
$variableName = $plugin . '_' . $variable is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2738
    $result = api_get_setting($variableName);
2739
2740
    if (isset($result[$plugin])) {
2741
        $value = $result[$plugin];
2742
2743
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2744
2745
        if (false !== $unserialized) {
2746
            $value = $unserialized;
2747
        }
2748
2749
        return $value;
2750
    }
2751
2752
    return null;
2753
}
2754
2755
/**
2756
 * Returns the value of a setting from the web-adjustable admin config settings.
2757
 */
2758
function api_get_settings_params($params)
2759
{
2760
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2761
2762
    return Database::select('*', $table, ['where' => $params]);
2763
}
2764
2765
/**
2766
 * @param array $params example: [id = ? => '1']
2767
 *
2768
 * @return array
2769
 */
2770
function api_get_settings_params_simple($params)
2771
{
2772
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2773
2774
    return Database::select('*', $table, ['where' => $params], 'one');
2775
}
2776
2777
/**
2778
 * Returns the value of a setting from the web-adjustable admin config settings.
2779
 */
2780
function api_delete_settings_params($params)
2781
{
2782
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2783
2784
    return Database::delete($table, $params);
2785
}
2786
2787
/**
2788
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2789
 *
2790
 * @return string Escaped version of $_SERVER['PHP_SELF']
2791
 */
2792
function api_get_self()
2793
{
2794
    return htmlentities($_SERVER['PHP_SELF']);
2795
}
2796
2797
/**
2798
 * Checks whether current user is a platform administrator.
2799
 *
2800
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2801
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2802
 *
2803
 * @return bool true if the user has platform admin rights,
2804
 *              false otherwise
2805
 *
2806
 * @see usermanager::is_admin(user_id) for a user-id specific function
2807
 */
2808
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2809
{
2810
    $currentUser = api_get_current_user();
2811
2812
    if (null === $currentUser) {
2813
        return false;
2814
    }
2815
2816
    $isAdmin = Session::read('is_platformAdmin');
2817
    if ($isAdmin) {
2818
        return true;
2819
    }
2820
    $user = api_get_user_info();
2821
2822
    return
2823
        isset($user['status']) &&
2824
        (
2825
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
2826
            ($allowDrh && DRH == $user['status'])
2827
        );
2828
}
2829
2830
/**
2831
 * Checks whether the user given as user id is in the admin table.
2832
 *
2833
 * @param int $user_id If none provided, will use current user
2834
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2835
 *
2836
 * @return bool True if the user is admin, false otherwise
2837
 */
2838
function api_is_platform_admin_by_id($user_id = null, $url = null)
2839
{
2840
    $user_id = (int) $user_id;
2841
    if (empty($user_id)) {
2842
        $user_id = api_get_user_id();
2843
    }
2844
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2845
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2846
    $res = Database::query($sql);
2847
    $is_admin = 1 === Database::num_rows($res);
2848
    if (!$is_admin || !isset($url)) {
2849
        return $is_admin;
2850
    }
2851
    // We get here only if $url is set
2852
    $url = (int) $url;
2853
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2854
    $sql = "SELECT * FROM $url_user_table
2855
            WHERE access_url_id = $url AND user_id = $user_id";
2856
    $res = Database::query($sql);
2857
2858
    return 1 === Database::num_rows($res);
2859
}
2860
2861
/**
2862
 * Returns the user's numeric status ID from the users table.
2863
 *
2864
 * @param int $user_id If none provided, will use current user
2865
 *
2866
 * @return int User's status (1 for teacher, 5 for student, etc)
2867
 */
2868
function api_get_user_status($user_id = null)
2869
{
2870
    $user_id = (int) $user_id;
2871
    if (empty($user_id)) {
2872
        $user_id = api_get_user_id();
2873
    }
2874
    $table = Database::get_main_table(TABLE_MAIN_USER);
2875
    $sql = "SELECT status FROM $table WHERE id = $user_id ";
2876
    $result = Database::query($sql);
2877
    $status = null;
2878
    if (Database::num_rows($result)) {
2879
        $row = Database::fetch_array($result);
2880
        $status = $row['status'];
2881
    }
2882
2883
    return $status;
2884
}
2885
2886
/**
2887
 * Checks whether current user is allowed to create courses.
2888
 *
2889
 * @return bool true if the user has course creation rights,
2890
 *              false otherwise
2891
 */
2892
function api_is_allowed_to_create_course()
2893
{
2894
    if (api_is_platform_admin()) {
2895
        return true;
2896
    }
2897
2898
    // Teachers can only create courses
2899
    if (api_is_teacher()) {
2900
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
2901
            return true;
2902
        } else {
2903
            return false;
2904
        }
2905
    }
2906
2907
    return Session::read('is_allowedCreateCourse');
2908
}
2909
2910
/**
2911
 * Checks whether the current user is a course administrator.
2912
 *
2913
 * @return bool True if current user is a course administrator
2914
 */
2915
function api_is_course_admin()
2916
{
2917
    if (api_is_platform_admin()) {
2918
        return true;
2919
    }
2920
2921
    $user = api_get_current_user();
2922
    if ($user) {
2923
        if (
2924
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
2925
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
2926
        ) {
2927
            return true;
2928
        }
2929
    }
2930
2931
    return false;
2932
}
2933
2934
/**
2935
 * Checks whether the current user is a course coach
2936
 * Based on the presence of user in session.id_coach (session general coach).
2937
 *
2938
 * @return bool True if current user is a course coach
2939
 */
2940
function api_is_session_general_coach()
2941
{
2942
    return Session::read('is_session_general_coach');
2943
}
2944
2945
/**
2946
 * Checks whether the current user is a course tutor
2947
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
2948
 *
2949
 * @return bool True if current user is a course tutor
2950
 */
2951
function api_is_course_tutor()
2952
{
2953
    return Session::read('is_courseTutor');
2954
}
2955
2956
/**
2957
 * @param int $user_id
2958
 * @param int $courseId
2959
 * @param int $session_id
2960
 *
2961
 * @return bool
2962
 */
2963
function api_is_course_session_coach($user_id, $courseId, $session_id)
2964
{
2965
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2966
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2967
2968
    $user_id = (int) $user_id;
2969
    $session_id = (int) $session_id;
2970
    $courseId = (int) $courseId;
2971
2972
    $sql = "SELECT DISTINCT session.id
2973
            FROM $session_table
2974
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2975
            ON session.id = session_rc_ru.session_id
2976
            WHERE
2977
                session_rc_ru.user_id = '".$user_id."'  AND
2978
                session_rc_ru.c_id = '$courseId' AND
2979
                session_rc_ru.status = 2 AND
2980
                session_rc_ru.session_id = '$session_id'";
2981
    $result = Database::query($sql);
2982
2983
    return Database::num_rows($result) > 0;
2984
}
2985
2986
/**
2987
 * Checks whether the current user is a course or session coach.
2988
 *
2989
 * @param int $session_id
2990
 * @param int $courseId
2991
 * @param bool  Check whether we are in student view and, if we are, return false
2992
 * @param int $userId
2993
 *
2994
 * @return bool True if current user is a course or session coach
2995
 */
2996
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
2997
{
2998
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2999
3000
    if (!empty($session_id)) {
3001
        $session_id = (int) $session_id;
3002
    } else {
3003
        $session_id = api_get_session_id();
3004
    }
3005
3006
    // The student preview was on
3007
    if ($check_student_view && api_is_student_view_active()) {
3008
        return false;
3009
    }
3010
3011
    if (!empty($courseId)) {
3012
        $courseId = (int) $courseId;
3013
    } else {
3014
        $courseId = api_get_course_int_id();
3015
    }
3016
3017
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3018
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3019
    $sessionIsCoach = [];
3020
3021
    if (!empty($courseId)) {
3022
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3023
                FROM $session_table s
3024
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3025
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3026
                WHERE
3027
                    session_rc_ru.c_id = '$courseId' AND
3028
                    session_rc_ru.status = 2 AND
3029
                    session_rc_ru.session_id = '$session_id'";
3030
        $result = Database::query($sql);
3031
        $sessionIsCoach = Database::store_result($result);
3032
    }
3033
3034
    if (!empty($session_id)) {
3035
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3036
                FROM $session_table
3037
                WHERE session.id_coach = $userId AND id = $session_id
3038
                ORDER BY access_start_date, access_end_date, name";
3039
        $result = Database::query($sql);
3040
        if (!empty($sessionIsCoach)) {
3041
            $sessionIsCoach = array_merge(
3042
                $sessionIsCoach,
3043
                Database::store_result($result)
3044
            );
3045
        } else {
3046
            $sessionIsCoach = Database::store_result($result);
3047
        }
3048
    }
3049
3050
    return count($sessionIsCoach) > 0;
3051
}
3052
3053
/**
3054
 * Checks whether the current user is a session administrator.
3055
 *
3056
 * @return bool True if current user is a course administrator
3057
 */
3058
function api_is_session_admin()
3059
{
3060
    $user = api_get_user_info();
3061
3062
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3063
}
3064
3065
/**
3066
 * Checks whether the current user is a human resources manager.
3067
 *
3068
 * @return bool True if current user is a human resources manager
3069
 */
3070
function api_is_drh()
3071
{
3072
    $user = api_get_user_info();
3073
3074
    return isset($user['status']) && DRH == $user['status'];
3075
}
3076
3077
/**
3078
 * Checks whether the current user is a student.
3079
 *
3080
 * @return bool True if current user is a human resources manager
3081
 */
3082
function api_is_student()
3083
{
3084
    $user = api_get_user_info();
3085
3086
    return isset($user['status']) && STUDENT == $user['status'];
3087
}
3088
3089
/**
3090
 * Checks whether the current user has the status 'teacher'.
3091
 *
3092
 * @return bool True if current user is a human resources manager
3093
 */
3094
function api_is_teacher()
3095
{
3096
    $user = api_get_user_info();
3097
3098
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3099
}
3100
3101
/**
3102
 * Checks whether the current user is a invited user.
3103
 *
3104
 * @return bool
3105
 */
3106
function api_is_invitee()
3107
{
3108
    $user = api_get_user_info();
3109
3110
    return isset($user['status']) && INVITEE == $user['status'];
3111
}
3112
3113
/**
3114
 * This function checks whether a session is assigned into a category.
3115
 *
3116
 * @param int       - session id
0 ignored issues
show
Documentation Bug introduced by
The doc comment - at position 0 could not be parsed: Unknown type name '-' at position 0 in -.
Loading history...
3117
 * @param string    - category name
3118
 *
3119
 * @return bool - true if is found, otherwise false
3120
 */
3121
function api_is_session_in_category($session_id, $category_name)
3122
{
3123
    $session_id = (int) $session_id;
3124
    $category_name = Database::escape_string($category_name);
3125
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3126
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3127
3128
    $sql = "SELECT 1
3129
            FROM $tbl_session
3130
            WHERE $session_id IN (
3131
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3132
                WHERE
3133
                  s.session_category_id = sc.id AND
3134
                  sc.name LIKE '%$category_name'
3135
            )";
3136
    $rs = Database::query($sql);
3137
3138
    if (Database::num_rows($rs) > 0) {
3139
        return true;
3140
    }
3141
3142
    return false;
3143
}
3144
3145
/**
3146
 * Displays options for switching between student view and course manager view.
3147
 *
3148
 * Changes in version 1.2 (Patrick Cool)
3149
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3150
 * is changed explicitly
3151
 *
3152
 * Changes in version 1.1 (Patrick Cool)
3153
 * student view now works correctly in subfolders of the document tool
3154
 * student view works correctly in the new links tool
3155
 *
3156
 * Example code for using this in your tools:
3157
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3158
 * //   display_tool_view_option($isStudentView);
3159
 * //}
3160
 * //and in later sections, use api_is_allowed_to_edit()
3161
 *
3162
 * @author Roan Embrechts
3163
 * @author Patrick Cool
3164
 * @author Julio Montoya, changes added in Chamilo
3165
 *
3166
 * @version 1.2
3167
 *
3168
 * @todo rewrite code so it is easier to understand
3169
 */
3170
function api_display_tool_view_option()
3171
{
3172
    if ('true' != api_get_setting('student_view_enabled')) {
3173
        return '';
3174
    }
3175
3176
    $sourceurl = '';
3177
    $is_framed = false;
3178
    // Exceptions apply for all multi-frames pages
3179
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3180
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3181
        return '';
3182
    }
3183
3184
    // Uncomment to remove student view link from document view page
3185
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3186
        if (empty($_GET['lp_id'])) {
3187
            return '';
3188
        }
3189
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3190
        $sourceurl = str_replace(
3191
            'lp/lp_header.php',
3192
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3193
            $sourceurl
3194
        );
3195
        //showinframes doesn't handle student view anyway...
3196
        //return '';
3197
        $is_framed = true;
3198
    }
3199
3200
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3201
    if (!$is_framed) {
3202
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3203
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3204
        } else {
3205
            $sourceurl = $_SERVER['REQUEST_URI'];
3206
        }
3207
    }
3208
3209
    $output_string = '';
3210
    if (!empty($_SESSION['studentview'])) {
3211
        if ('studentview' == $_SESSION['studentview']) {
3212
            // We have to remove the isStudentView=true from the $sourceurl
3213
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3214
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3215
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3216
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3217
        } elseif ('teacherview' == $_SESSION['studentview']) {
3218
            // Switching to teacherview
3219
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3220
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3221
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3222
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3223
        }
3224
    } else {
3225
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3226
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3227
    }
3228
    $output_string = Security::remove_XSS($output_string);
3229
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3230
3231
    return $html;
3232
}
3233
3234
/**
3235
 * Function that removes the need to directly use is_courseAdmin global in
3236
 * tool scripts. It returns true or false depending on the user's rights in
3237
 * this particular course.
3238
 * Optionally checking for tutor and coach roles here allows us to use the
3239
 * student_view feature altogether with these roles as well.
3240
 *
3241
 * @param bool  Whether to check if the user has the tutor role
3242
 * @param bool  Whether to check if the user has the coach role
3243
 * @param bool  Whether to check if the user has the session coach role
3244
 * @param bool  check the student view or not
3245
 *
3246
 * @author Roan Embrechts
3247
 * @author Patrick Cool
3248
 * @author Julio Montoya
3249
 *
3250
 * @version 1.1, February 2004
3251
 *
3252
 * @return bool true: the user has the rights to edit, false: he does not
3253
 */
3254
function api_is_allowed_to_edit(
3255
    $tutor = false,
3256
    $coach = false,
3257
    $session_coach = false,
3258
    $check_student_view = true
3259
) {
3260
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3261
    // Admins can edit anything.
3262
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3263
        //The student preview was on
3264
        if ($check_student_view && api_is_student_view_active()) {
3265
            return false;
3266
        }
3267
3268
        return true;
3269
    }
3270
3271
    $sessionId = api_get_session_id();
3272
3273
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3274
        $efv = new ExtraFieldValue('course');
3275
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3276
            api_get_course_int_id(),
3277
            'session_courses_read_only_mode'
3278
        );
3279
3280
        if (!empty($lockExrafieldField['value'])) {
3281
            return false;
3282
        }
3283
    }
3284
3285
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3286
    $session_visibility = api_get_session_visibility($sessionId);
3287
    $is_courseAdmin = api_is_course_admin();
3288
3289
    if (!$is_courseAdmin && $tutor) {
3290
        // If we also want to check if the user is a tutor...
3291
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3292
    }
3293
3294
    if (!$is_courseAdmin && $coach) {
3295
        // If we also want to check if the user is a coach...';
3296
        // Check if session visibility is read only for coaches.
3297
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3298
            $is_allowed_coach_to_edit = false;
3299
        }
3300
3301
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3302
            // Check if coach is allowed to edit a course.
3303
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3304
        }
3305
    }
3306
3307
    if (!$is_courseAdmin && $session_coach) {
3308
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3309
    }
3310
3311
    // Check if the student_view is enabled, and if so, if it is activated.
3312
    if ('true' === api_get_setting('student_view_enabled')) {
3313
        $studentView = api_is_student_view_active();
3314
        if (!empty($sessionId)) {
3315
            // Check if session visibility is read only for coaches.
3316
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3317
                $is_allowed_coach_to_edit = false;
3318
            }
3319
3320
            $is_allowed = false;
3321
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3322
                // Check if coach is allowed to edit a course.
3323
                $is_allowed = $is_allowed_coach_to_edit;
3324
            }
3325
            if ($check_student_view) {
3326
                $is_allowed = $is_allowed && false === $studentView;
3327
            }
3328
        } else {
3329
            $is_allowed = $is_courseAdmin;
3330
            if ($check_student_view) {
3331
                $is_allowed = $is_courseAdmin && false === $studentView;
3332
            }
3333
        }
3334
3335
        return $is_allowed;
3336
    } else {
3337
        return $is_courseAdmin;
3338
    }
3339
}
3340
3341
/**
3342
 * Returns true if user is a course coach of at least one course in session.
3343
 *
3344
 * @param int $sessionId
3345
 *
3346
 * @return bool
3347
 */
3348
function api_is_coach_of_course_in_session($sessionId)
3349
{
3350
    if (api_is_platform_admin()) {
3351
        return true;
3352
    }
3353
3354
    $userId = api_get_user_id();
3355
    $courseList = UserManager::get_courses_list_by_session(
3356
        $userId,
3357
        $sessionId
3358
    );
3359
3360
    // Session visibility.
3361
    $visibility = api_get_session_visibility(
3362
        $sessionId,
3363
        null,
3364
        false
3365
    );
3366
3367
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3368
        // Course Coach session visibility.
3369
        $blockedCourseCount = 0;
3370
        $closedVisibilityList = [
3371
            COURSE_VISIBILITY_CLOSED,
3372
            COURSE_VISIBILITY_HIDDEN,
3373
        ];
3374
3375
        foreach ($courseList as $course) {
3376
            // Checking session visibility
3377
            $sessionCourseVisibility = api_get_session_visibility(
3378
                $sessionId,
3379
                $course['real_id']
3380
            );
3381
3382
            $courseIsVisible = !in_array(
3383
                $course['visibility'],
3384
                $closedVisibilityList
3385
            );
3386
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3387
                $blockedCourseCount++;
3388
            }
3389
        }
3390
3391
        // If all courses are blocked then no show in the list.
3392
        if ($blockedCourseCount === count($courseList)) {
3393
            $visibility = SESSION_INVISIBLE;
3394
        } else {
3395
            $visibility = SESSION_VISIBLE;
3396
        }
3397
    }
3398
3399
    switch ($visibility) {
3400
        case SESSION_VISIBLE_READ_ONLY:
3401
        case SESSION_VISIBLE:
3402
        case SESSION_AVAILABLE:
3403
            return true;
3404
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
3405
        case SESSION_INVISIBLE:
3406
            return false;
3407
    }
3408
3409
    return false;
3410
}
3411
3412
/**
3413
 * Checks if a student can edit contents in a session depending
3414
 * on the session visibility.
3415
 *
3416
 * @param bool $tutor Whether to check if the user has the tutor role
3417
 * @param bool $coach Whether to check if the user has the coach role
3418
 *
3419
 * @return bool true: the user has the rights to edit, false: he does not
3420
 */
3421
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3422
{
3423
    if (api_is_allowed_to_edit($tutor, $coach)) {
3424
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3425
        return true;
3426
    } else {
3427
        $sessionId = api_get_session_id();
3428
3429
        if (0 == $sessionId) {
3430
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3431
            return true;
3432
        } else {
3433
            // I'm in a session and I'm a student
3434
            // Get the session visibility
3435
            $session_visibility = api_get_session_visibility($sessionId);
3436
            // if 5 the session is still available
3437
            switch ($session_visibility) {
3438
                case SESSION_VISIBLE_READ_ONLY: // 1
3439
                    return false;
3440
                case SESSION_VISIBLE:           // 2
3441
                    return true;
3442
                case SESSION_INVISIBLE:         // 3
3443
                    return false;
3444
                case SESSION_AVAILABLE:         //5
3445
                    return true;
3446
            }
3447
        }
3448
    }
3449
3450
    return false;
3451
}
3452
3453
/**
3454
 * Current user is anon?
3455
 *
3456
 * @return bool true if this user is anonymous, false otherwise
3457
 */
3458
function api_is_anonymous()
3459
{
3460
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3461
}
3462
3463
/**
3464
 * Displays message "You are not allowed here..." and exits the entire script.
3465
 *
3466
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3467
 * @param string $message
3468
 * @param int    $responseCode
3469
 */
3470
function api_not_allowed(
3471
    $print_headers = false,
3472
    $message = null,
3473
    $responseCode = 0
3474
) {
3475
    throw new Exception('You are not allowed');
3476
}
3477
3478
/**
3479
 * @param string $languageIsoCode
3480
 *
3481
 * @return string
3482
 */
3483
function languageToCountryIsoCode($languageIsoCode)
3484
{
3485
    $allow = api_get_configuration_value('language_flags_by_country');
3486
3487
    // @todo save in DB
3488
    switch ($languageIsoCode) {
3489
        case 'ar':
3490
            $country = 'ae';
3491
            break;
3492
        case 'bs':
3493
            $country = 'ba';
3494
            break;
3495
        case 'ca':
3496
            $country = 'es';
3497
            if ($allow) {
3498
                $country = 'catalan';
3499
            }
3500
            break;
3501
        case 'cs':
3502
            $country = 'cz';
3503
            break;
3504
        case 'da':
3505
            $country = 'dk';
3506
            break;
3507
        case 'el':
3508
            $country = 'ae';
3509
            break;
3510
        case 'en':
3511
            $country = 'gb';
3512
            break;
3513
        case 'eu': // Euskera
3514
            $country = 'es';
3515
            if ($allow) {
3516
                $country = 'basque';
3517
            }
3518
            break;
3519
        case 'gl': // galego
3520
            $country = 'es';
3521
            if ($allow) {
3522
                $country = 'galician';
3523
            }
3524
            break;
3525
        case 'he':
3526
            $country = 'il';
3527
            break;
3528
        case 'ja':
3529
            $country = 'jp';
3530
            break;
3531
        case 'ka':
3532
            $country = 'ge';
3533
            break;
3534
        case 'ko':
3535
            $country = 'kr';
3536
            break;
3537
        case 'ms':
3538
            $country = 'my';
3539
            break;
3540
        case 'pt-BR':
3541
            $country = 'br';
3542
            break;
3543
        case 'qu':
3544
            $country = 'pe';
3545
            break;
3546
        case 'sl':
3547
            $country = 'si';
3548
            break;
3549
        case 'sv':
3550
            $country = 'se';
3551
            break;
3552
        case 'uk': // Ukraine
3553
            $country = 'ua';
3554
            break;
3555
        case 'zh-TW':
3556
        case 'zh':
3557
            $country = 'cn';
3558
            break;
3559
        default:
3560
            $country = $languageIsoCode;
3561
            break;
3562
    }
3563
    $country = strtolower($country);
3564
3565
    return $country;
3566
}
3567
3568
/**
3569
 * Returns a list of all the languages that are made available by the admin.
3570
 *
3571
 * @return array An array with all languages. Structure of the array is
3572
 *               array['name'] = An array with the name of every language
3573
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
3574
 */
3575
function api_get_languages()
3576
{
3577
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3578
    $sql = "SELECT * FROM $table WHERE available='1'
3579
            ORDER BY original_name ASC";
3580
    $result = Database::query($sql);
3581
    $languages = [];
3582
    while ($row = Database::fetch_array($result, 'ASSOC')) {
3583
        $languages[$row['isocode']] = $row['original_name'];
3584
    }
3585
3586
    return $languages;
3587
}
3588
3589
/**
3590
 * Returns the id (the database id) of a language.
3591
 *
3592
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
3593
 *
3594
 * @return int id of the language
3595
 */
3596
function api_get_language_id($language)
3597
{
3598
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3599
    if (empty($language)) {
3600
        return null;
3601
    }
3602
    $language = Database::escape_string($language);
3603
    $sql = "SELECT id FROM $tbl_language
3604
            WHERE english_name = '$language' LIMIT 1";
3605
    $result = Database::query($sql);
3606
    $row = Database::fetch_array($result);
3607
3608
    return $row['id'];
3609
}
3610
3611
/**
3612
 * Get the language information by its id.
3613
 *
3614
 * @param int $languageId
3615
 *
3616
 * @throws Exception
3617
 *
3618
 * @return array
3619
 */
3620
function api_get_language_info($languageId)
3621
{
3622
    if (empty($languageId)) {
3623
        return [];
3624
    }
3625
3626
    $language = Database::getManager()->find(Language::class, $languageId);
3627
3628
    if (!$language) {
3629
        return [];
3630
    }
3631
3632
    return [
3633
        'id' => $language->getId(),
3634
        'original_name' => $language->getOriginalName(),
3635
        'english_name' => $language->getEnglishName(),
3636
        'isocode' => $language->getIsocode(),
3637
        'available' => $language->getAvailable(),
3638
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
3639
    ];
3640
}
3641
3642
/**
3643
 * @param string $code
3644
 *
3645
 * @return Language
3646
 */
3647
function api_get_language_from_iso($code)
3648
{
3649
    $em = Database::getManager();
3650
3651
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
3652
}
3653
3654
/**
3655
 * Returns the name of the visual (CSS) theme to be applied on the current page.
3656
 * The returned name depends on the platform, course or user -wide settings.
3657
 *
3658
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
3659
 */
3660
function api_get_visual_theme()
3661
{
3662
    static $visual_theme;
3663
    if (!isset($visual_theme)) {
3664
        // Get style directly from DB
3665
        /*$styleFromDatabase = api_get_settings_params_simple(
3666
            [
3667
                'variable = ? AND access_url = ?' => [
3668
                    'stylesheets',
3669
                    api_get_current_access_url_id(),
3670
                ],
3671
            ]
3672
        );
3673
3674
        if ($styleFromDatabase) {
3675
            $platform_theme = $styleFromDatabase['selected_value'];
3676
        } else {
3677
            $platform_theme = api_get_setting('stylesheets');
3678
        }*/
3679
        $platform_theme = api_get_setting('stylesheets');
3680
3681
        // Platform's theme.
3682
        $visual_theme = $platform_theme;
3683
        if ('true' == api_get_setting('user_selected_theme')) {
3684
            $user_info = api_get_user_info();
3685
            if (isset($user_info['theme'])) {
3686
                $user_theme = $user_info['theme'];
3687
3688
                if (!empty($user_theme)) {
3689
                    $visual_theme = $user_theme;
3690
                    // User's theme.
3691
                }
3692
            }
3693
        }
3694
3695
        $course_id = api_get_course_id();
3696
        if (!empty($course_id)) {
3697
            if ('true' == api_get_setting('allow_course_theme')) {
3698
                $course_theme = api_get_course_setting('course_theme', $course_id);
3699
3700
                if (!empty($course_theme) && -1 != $course_theme) {
3701
                    if (!empty($course_theme)) {
3702
                        // Course's theme.
3703
                        $visual_theme = $course_theme;
3704
                    }
3705
                }
3706
3707
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
3708
                if (1 == $allow_lp_theme) {
3709
                    /*global $lp_theme_css, $lp_theme_config;
3710
                    // These variables come from the file lp_controller.php.
3711
                    if (!$lp_theme_config) {
3712
                        if (!empty($lp_theme_css)) {
3713
                            // LP's theme.
3714
                            $visual_theme = $lp_theme_css;
3715
                        }
3716
                    }*/
3717
                }
3718
            }
3719
        }
3720
3721
        if (empty($visual_theme)) {
3722
            $visual_theme = 'chamilo';
3723
        }
3724
3725
        /*global $lp_theme_log;
3726
        if ($lp_theme_log) {
3727
            $visual_theme = $platform_theme;
3728
        }*/
3729
    }
3730
3731
    return $visual_theme;
3732
}
3733
3734
/**
3735
 * Returns a list of CSS themes currently available in the CSS folder
3736
 * The folder must have a default.css file.
3737
 *
3738
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
3739
 *
3740
 * @return array list of themes directories from the css folder
3741
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
3742
 */
3743
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
3744
{
3745
    // This configuration value is set by the vchamilo plugin
3746
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
3747
3748
    $readCssFolder = function ($dir) use ($virtualTheme) {
3749
        $finder = new Finder();
3750
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
3751
        $list = [];
3752
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
3753
        foreach ($themes as $theme) {
3754
            $folder = $theme->getFilename();
3755
            // A theme folder is consider if there's a default.css file
3756
            if (!file_exists($theme->getPathname().'/default.css')) {
3757
                continue;
3758
            }
3759
            $name = ucwords(str_replace('_', ' ', $folder));
3760
            if ($folder == $virtualTheme) {
3761
                continue;
3762
            }
3763
            $list[$folder] = $name;
3764
        }
3765
3766
        return $list;
3767
    };
3768
3769
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
3770
    $list = $readCssFolder($dir);
3771
3772
    if (!empty($virtualTheme)) {
3773
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
3774
        if ($getOnlyThemeFromVirtualInstance) {
3775
            return $newList;
3776
        }
3777
        $list = $list + $newList;
3778
        asort($list);
3779
    }
3780
3781
    return $list;
3782
}
3783
3784
/**
3785
 * Find the largest sort value in a given user_course_category
3786
 * This function is used when we are moving a course to a different category
3787
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
3788
 *
3789
 * @param int $courseCategoryId the id of the user_course_category
3790
 * @param int $userId
3791
 *
3792
 * @return int the value of the highest sort of the user_course_category
3793
 */
3794
function api_max_sort_value($courseCategoryId, $userId)
3795
{
3796
    $user = api_get_user_entity($userId);
3797
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
3798
3799
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
3800
}
3801
3802
/**
3803
 * Transforms a number of seconds in hh:mm:ss format.
3804
 *
3805
 * @author Julian Prud'homme
3806
 *
3807
 * @param int    $seconds      number of seconds
3808
 * @param string $space
3809
 * @param bool   $showSeconds
3810
 * @param bool   $roundMinutes
3811
 *
3812
 * @return string the formatted time
3813
 */
3814
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
3815
{
3816
    // $seconds = -1 means that we have wrong data in the db.
3817
    if (-1 == $seconds) {
3818
        return
3819
            get_lang('Unknown').
3820
            Display::return_icon(
3821
                'info2.gif',
3822
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
3823
                ['align' => 'absmiddle', 'hspace' => '3px']
3824
            );
3825
    }
3826
3827
    // How many hours ?
3828
    $hours = floor($seconds / 3600);
3829
3830
    // How many minutes ?
3831
    $min = floor(($seconds - ($hours * 3600)) / 60);
3832
3833
    if ($roundMinutes) {
3834
        if ($min >= 45) {
3835
            $min = 45;
3836
        }
3837
3838
        if ($min >= 30 && $min <= 44) {
3839
            $min = 30;
3840
        }
3841
3842
        if ($min >= 15 && $min <= 29) {
3843
            $min = 15;
3844
        }
3845
3846
        if ($min >= 0 && $min <= 14) {
3847
            $min = 0;
3848
        }
3849
    }
3850
3851
    // How many seconds
3852
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
3853
3854
    if ($hours < 10) {
3855
        $hours = "0$hours";
3856
    }
3857
3858
    if ($sec < 10) {
3859
        $sec = "0$sec";
3860
    }
3861
3862
    if ($min < 10) {
3863
        $min = "0$min";
3864
    }
3865
3866
    $seconds = '';
3867
    if ($showSeconds) {
3868
        $seconds = $space.$sec;
3869
    }
3870
3871
    return $hours.$space.$min.$seconds;
3872
}
3873
3874
/**
3875
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3876
 * The return value is based on the platform administrator's setting
3877
 * "Administration > Configuration settings > Security > Permissions for new directories".
3878
 *
3879
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
3880
 */
3881
function api_get_permissions_for_new_directories()
3882
{
3883
    static $permissions;
3884
    if (!isset($permissions)) {
3885
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
3886
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
3887
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
3888
    }
3889
3890
    return $permissions;
3891
}
3892
3893
/**
3894
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3895
 * The return value is based on the platform administrator's setting
3896
 * "Administration > Configuration settings > Security > Permissions for new files".
3897
 *
3898
 * @return int returns the permissions in the format
3899
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
3900
 */
3901
function api_get_permissions_for_new_files()
3902
{
3903
    static $permissions;
3904
    if (!isset($permissions)) {
3905
        $permissions = trim(api_get_setting('permissions_for_new_files'));
3906
        // The default value 0666 is according to that in the platform
3907
        // administration panel after fresh system installation.
3908
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
3909
    }
3910
3911
    return $permissions;
3912
}
3913
3914
/**
3915
 * Deletes a file, or a folder and its contents.
3916
 *
3917
 * @author      Aidan Lister <[email protected]>
3918
 *
3919
 * @version     1.0.3
3920
 *
3921
 * @param string $dirname Directory to delete
3922
 * @param       bool     Deletes only the content or not
3923
 * @param bool $strict if one folder/file fails stop the loop
3924
 *
3925
 * @return bool Returns TRUE on success, FALSE on failure
3926
 *
3927
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
3928
 *
3929
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
3930
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
3931
 */
3932
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
3933
{
3934
    $res = true;
3935
    // A sanity check.
3936
    if (!file_exists($dirname)) {
3937
        return false;
3938
    }
3939
    $php_errormsg = '';
3940
    // Simple delete for a file.
3941
    if (is_file($dirname) || is_link($dirname)) {
3942
        $res = unlink($dirname);
3943
        if (false === $res) {
3944
            error_log(__FILE__.' line '.__LINE__.': '.((bool) ini_get('track_errors') ? $php_errormsg : 'Error not recorded because track_errors is off in your php.ini'), 0);
3945
        }
3946
3947
        return $res;
3948
    }
3949
3950
    // Loop through the folder.
3951
    $dir = dir($dirname);
3952
    // A sanity check.
3953
    $is_object_dir = is_object($dir);
3954
    if ($is_object_dir) {
3955
        while (false !== $entry = $dir->read()) {
3956
            // Skip pointers.
3957
            if ('.' == $entry || '..' == $entry) {
3958
                continue;
3959
            }
3960
3961
            // Recurse.
3962
            if ($strict) {
3963
                $result = rmdirr("$dirname/$entry");
3964
                if (false == $result) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
3965
                    $res = false;
3966
                    break;
3967
                }
3968
            } else {
3969
                rmdirr("$dirname/$entry");
3970
            }
3971
        }
3972
    }
3973
3974
    // Clean up.
3975
    if ($is_object_dir) {
3976
        $dir->close();
3977
    }
3978
3979
    if (false == $delete_only_content_in_folder) {
3980
        $res = rmdir($dirname);
3981
        if (false === $res) {
3982
            error_log(__FILE__.' line '.__LINE__.': '.((bool) ini_get('track_errors') ? $php_errormsg : 'error not recorded because track_errors is off in your php.ini'), 0);
3983
        }
3984
    }
3985
3986
    return $res;
3987
}
3988
3989
// TODO: This function is to be simplified. File access modes to be implemented.
3990
/**
3991
 * function adapted from a php.net comment
3992
 * copy recursively a folder.
3993
 *
3994
 * @param the source folder
3995
 * @param the dest folder
3996
 * @param an array of excluded file_name (without extension)
3997
 * @param copied_files the returned array of copied files
3998
 * @param string $source
3999
 * @param string $dest
4000
 */
4001
function copyr($source, $dest, $exclude = [], $copied_files = [])
4002
{
4003
    if (empty($dest)) {
4004
        return false;
4005
    }
4006
    // Simple copy for a file
4007
    if (is_file($source)) {
4008
        $path_info = pathinfo($source);
4009
        if (!in_array($path_info['filename'], $exclude)) {
4010
            copy($source, $dest);
4011
        }
4012
4013
        return true;
4014
    } elseif (!is_dir($source)) {
4015
        //then source is not a dir nor a file, return
4016
        return false;
4017
    }
4018
4019
    // Make destination directory.
4020
    if (!is_dir($dest)) {
4021
        mkdir($dest, api_get_permissions_for_new_directories());
4022
    }
4023
4024
    // Loop through the folder.
4025
    $dir = dir($source);
4026
    while (false !== $entry = $dir->read()) {
4027
        // Skip pointers
4028
        if ('.' == $entry || '..' == $entry) {
4029
            continue;
4030
        }
4031
4032
        // Deep copy directories.
4033
        if ($dest !== "$source/$entry") {
4034
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4035
        }
4036
    }
4037
    // Clean up.
4038
    $dir->close();
4039
4040
    return true;
4041
}
4042
4043
/**
4044
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4045
 * Documentation header to be added here.
4046
 *
4047
 * @param string $pathname
4048
 * @param string $base_path_document
4049
 * @param int    $session_id
4050
 *
4051
 * @return mixed True if directory already exists, false if a file already exists at
4052
 *               the destination and null if everything goes according to plan
4053
 */
4054
function copy_folder_course_session(
4055
    $pathname,
4056
    $base_path_document,
4057
    $session_id,
4058
    $course_info,
4059
    $document,
4060
    $source_course_id
4061
) {
4062
    $table = Database::get_course_table(TABLE_DOCUMENT);
4063
    $session_id = intval($session_id);
4064
    $source_course_id = intval($source_course_id);
4065
4066
    // Check whether directory already exists.
4067
    if (is_dir($pathname) || empty($pathname)) {
4068
        return true;
4069
    }
4070
4071
    // Ensure that a file with the same name does not already exist.
4072
    if (is_file($pathname)) {
4073
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4074
4075
        return false;
4076
    }
4077
4078
    $course_id = $course_info['real_id'];
4079
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4080
    $new_pathname = $base_path_document;
4081
    $path = '';
4082
4083
    foreach ($folders as $folder) {
4084
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4085
        $path .= DIRECTORY_SEPARATOR.$folder;
4086
4087
        if (!file_exists($new_pathname)) {
4088
            $path = Database::escape_string($path);
4089
4090
            $sql = "SELECT * FROM $table
4091
                    WHERE
4092
                        c_id = $source_course_id AND
4093
                        path = '$path' AND
4094
                        filetype = 'folder' AND
4095
                        session_id = '$session_id'";
4096
            $rs1 = Database::query($sql);
4097
            $num_rows = Database::num_rows($rs1);
4098
4099
            if (0 == $num_rows) {
4100
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4101
4102
                // Insert new folder with destination session_id.
4103
                $params = [
4104
                    'c_id' => $course_id,
4105
                    'path' => $path,
4106
                    'comment' => $document->comment,
4107
                    'title' => basename($new_pathname),
4108
                    'filetype' => 'folder',
4109
                    'size' => '0',
4110
                    'session_id' => $session_id,
4111
                ];
4112
                Database::insert($table, $params);
4113
            }
4114
        }
4115
    } // en foreach
4116
}
4117
4118
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4119
/**
4120
 * @param string $path
4121
 */
4122
function api_chmod_R($path, $filemode)
4123
{
4124
    if (!is_dir($path)) {
4125
        return chmod($path, $filemode);
4126
    }
4127
4128
    $handler = opendir($path);
4129
    while ($file = readdir($handler)) {
4130
        if ('.' != $file && '..' != $file) {
4131
            $fullpath = "$path/$file";
4132
            if (!is_dir($fullpath)) {
4133
                if (!chmod($fullpath, $filemode)) {
4134
                    return false;
4135
                }
4136
            } else {
4137
                if (!api_chmod_R($fullpath, $filemode)) {
4138
                    return false;
4139
                }
4140
            }
4141
        }
4142
    }
4143
4144
    closedir($handler);
4145
4146
    return chmod($path, $filemode);
4147
}
4148
4149
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4150
/**
4151
 * Parse info file format. (e.g: file.info).
4152
 *
4153
 * Files should use an ini-like format to specify values.
4154
 * White-space generally doesn't matter, except inside values.
4155
 * e.g.
4156
 *
4157
 * @verbatim
4158
 *   key = value
4159
 *   key = "value"
4160
 *   key = 'value'
4161
 *   key = "multi-line
4162
 *
4163
 *   value"
4164
 *   key = 'multi-line
4165
 *
4166
 *   value'
4167
 *   key
4168
 *   =
4169
 *   'value'
4170
 * @endverbatim
4171
 *
4172
 * Arrays are created using a GET-like syntax:
4173
 *
4174
 * @verbatim
4175
 *   key[] = "numeric array"
4176
 *   key[index] = "associative array"
4177
 *   key[index][] = "nested numeric array"
4178
 *   key[index][index] = "nested associative array"
4179
 * @endverbatim
4180
 *
4181
 * PHP constants are substituted in, but only when used as the entire value:
4182
 *
4183
 * Comments should start with a semi-colon at the beginning of a line.
4184
 *
4185
 * This function is NOT for placing arbitrary module-specific settings. Use
4186
 * variable_get() and variable_set() for that.
4187
 *
4188
 * Information stored in the module.info file:
4189
 * - name: The real name of the module for display purposes.
4190
 * - description: A brief description of the module.
4191
 * - dependencies: An array of shortnames of other modules this module depends on.
4192
 * - package: The name of the package of modules this module belongs to.
4193
 *
4194
 * Example of .info file:
4195
 * <code>
4196
 * @verbatim
4197
 *   name = Forum
4198
 *   description = Enables threaded discussions about general topics.
4199
 *   dependencies[] = taxonomy
4200
 *   dependencies[] = comment
4201
 *   package = Core - optional
4202
 *   version = VERSION
4203
 * @endverbatim
4204
 * </code>
4205
 *
4206
 * @param string $filename
4207
 *                         The file we are parsing. Accepts file with relative or absolute path.
4208
 *
4209
 * @return
4210
 *   The info array
4211
 */
4212
function api_parse_info_file($filename)
4213
{
4214
    $info = [];
4215
4216
    if (!file_exists($filename)) {
4217
        return $info;
4218
    }
4219
4220
    $data = file_get_contents($filename);
4221
    if (preg_match_all('
4222
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4223
        ((?:
4224
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4225
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4226
        )+?)
4227
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4228
        (?:
4229
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4230
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4231
          ([^\r\n]*?)                   # Non-quoted string
4232
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4233
        @msx', $data, $matches, PREG_SET_ORDER)) {
4234
        $key = $value1 = $value2 = $value3 = '';
4235
        foreach ($matches as $match) {
4236
            // Fetch the key and value string.
4237
            $i = 0;
4238
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4239
                $$var = isset($match[++$i]) ? $match[$i] : '';
4240
            }
4241
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4242
4243
            // Parse array syntax.
4244
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4245
            $last = array_pop($keys);
4246
            $parent = &$info;
4247
4248
            // Create nested arrays.
4249
            foreach ($keys as $key) {
4250
                if ('' == $key) {
4251
                    $key = count($parent);
4252
                }
4253
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4254
                    $parent[$key] = [];
4255
                }
4256
                $parent = &$parent[$key];
4257
            }
4258
4259
            // Handle PHP constants.
4260
            if (defined($value)) {
4261
                $value = constant($value);
4262
            }
4263
4264
            // Insert actual value.
4265
            if ('' == $last) {
4266
                $last = count($parent);
4267
            }
4268
            $parent[$last] = $value;
4269
        }
4270
    }
4271
4272
    return $info;
4273
}
4274
4275
/**
4276
 * Gets Chamilo version from the configuration files.
4277
 *
4278
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4279
 */
4280
function api_get_version()
4281
{
4282
    return (string) api_get_configuration_value('system_version');
4283
}
4284
4285
/**
4286
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4287
 *
4288
 * @return string
4289
 */
4290
function api_get_software_name()
4291
{
4292
    $name = api_get_configuration_value('software_name');
4293
    if (!empty($name)) {
4294
        return $name;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $name also could return the type boolean which is incompatible with the documented return type string.
Loading history...
4295
    } else {
4296
        return 'Chamilo';
4297
    }
4298
}
4299
4300
function api_get_status_list()
4301
{
4302
    $list = [];
4303
    // Table of status
4304
    $list[COURSEMANAGER] = 'teacher'; // 1
4305
    $list[SESSIONADMIN] = 'session_admin'; // 3
4306
    $list[DRH] = 'drh'; // 4
4307
    $list[STUDENT] = 'user'; // 5
4308
    $list[ANONYMOUS] = 'anonymous'; // 6
4309
    $list[INVITEE] = 'invited'; // 20
4310
4311
    return $list;
4312
}
4313
4314
/**
4315
 * Checks whether status given in parameter exists in the platform.
4316
 *
4317
 * @param mixed the status (can be either int either string)
4318
 *
4319
 * @return bool if the status exists, else returns false
4320
 */
4321
function api_status_exists($status_asked)
4322
{
4323
    $list = api_get_status_list();
4324
4325
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4326
}
4327
4328
/**
4329
 * Checks whether status given in parameter exists in the platform. The function
4330
 * returns the status ID or false if it does not exist, but given the fact there
4331
 * is no "0" status, the return value can be checked against
4332
 * if(api_status_key()) to know if it exists.
4333
 *
4334
 * @param   mixed   The status (can be either int or string)
4335
 *
4336
 * @return mixed Status ID if exists, false otherwise
4337
 */
4338
function api_status_key($status)
4339
{
4340
    $list = api_get_status_list();
4341
4342
    return isset($list[$status]) ? $status : array_search($status, $list);
4343
}
4344
4345
/**
4346
 * Gets the status langvars list.
4347
 *
4348
 * @return string[] the list of status with their translations
4349
 */
4350
function api_get_status_langvars()
4351
{
4352
    return [
4353
        COURSEMANAGER => get_lang('Teacher'),
4354
        SESSIONADMIN => get_lang('SessionsAdmin'),
4355
        DRH => get_lang('Human Resources Manager'),
4356
        STUDENT => get_lang('Learner'),
4357
        ANONYMOUS => get_lang('Anonymous'),
4358
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4359
        INVITEE => get_lang('Invited'),
4360
    ];
4361
}
4362
4363
/**
4364
 * The function that retrieves all the possible settings for a certain config setting.
4365
 *
4366
 * @author Patrick Cool <[email protected]>, Ghent University
4367
 */
4368
function api_get_settings_options($var)
4369
{
4370
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4371
    $var = Database::escape_string($var);
4372
    $sql = "SELECT * FROM $table_settings_options
4373
            WHERE variable = '$var'
4374
            ORDER BY id";
4375
    $result = Database::query($sql);
4376
    $settings_options_array = [];
4377
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4378
        $settings_options_array[] = $row;
4379
    }
4380
4381
    return $settings_options_array;
4382
}
4383
4384
/**
4385
 * @param array $params
4386
 */
4387
function api_set_setting_option($params)
4388
{
4389
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4390
    if (empty($params['id'])) {
4391
        Database::insert($table, $params);
4392
    } else {
4393
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4394
    }
4395
}
4396
4397
/**
4398
 * @param array $params
4399
 */
4400
function api_set_setting_simple($params)
4401
{
4402
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4403
    $url_id = api_get_current_access_url_id();
4404
4405
    if (empty($params['id'])) {
4406
        $params['access_url'] = $url_id;
4407
        Database::insert($table, $params);
4408
    } else {
4409
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4410
    }
4411
}
4412
4413
/**
4414
 * @param int $id
4415
 */
4416
function api_delete_setting_option($id)
4417
{
4418
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4419
    if (!empty($id)) {
4420
        Database::delete($table, ['id = ? ' => $id]);
4421
    }
4422
}
4423
4424
/**
4425
 * Sets a platform configuration setting to a given value.
4426
 *
4427
 * @param string    The variable we want to update
4428
 * @param string    The value we want to record
4429
 * @param string    The sub-variable if any (in most cases, this will remain null)
4430
 * @param string    The category if any (in most cases, this will remain null)
4431
 * @param int       The access_url for which this parameter is valid
4432
 * @param string $cat
4433
 *
4434
 * @return bool|null
4435
 */
4436
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
4437
{
4438
    if (empty($var)) {
4439
        return false;
4440
    }
4441
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4442
    $var = Database::escape_string($var);
4443
    $value = Database::escape_string($value);
4444
    $access_url = (int) $access_url;
4445
    if (empty($access_url)) {
4446
        $access_url = 1;
4447
    }
4448
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
4449
    if (!empty($subvar)) {
4450
        $subvar = Database::escape_string($subvar);
4451
        $select .= " AND subkey = '$subvar'";
4452
    }
4453
    if (!empty($cat)) {
4454
        $cat = Database::escape_string($cat);
4455
        $select .= " AND category = '$cat'";
4456
    }
4457
    if ($access_url > 1) {
4458
        $select .= " AND access_url = $access_url";
4459
    } else {
4460
        $select .= " AND access_url = 1 ";
4461
    }
4462
4463
    $res = Database::query($select);
4464
    if (Database::num_rows($res) > 0) {
4465
        // Found item for this access_url.
4466
        $row = Database::fetch_array($res);
4467
        $sql = "UPDATE $t_settings SET selected_value = '$value'
4468
                WHERE id = ".$row['id'];
4469
        Database::query($sql);
4470
    } else {
4471
        // Item not found for this access_url, we have to check if it exist with access_url = 1
4472
        $select = "SELECT * FROM $t_settings
4473
                   WHERE variable = '$var' AND access_url = 1 ";
4474
        // Just in case
4475
        if (1 == $access_url) {
4476
            if (!empty($subvar)) {
4477
                $select .= " AND subkey = '$subvar'";
4478
            }
4479
            if (!empty($cat)) {
4480
                $select .= " AND category = '$cat'";
4481
            }
4482
            $res = Database::query($select);
4483
            if (Database::num_rows($res) > 0) {
4484
                // We have a setting for access_url 1, but none for the current one, so create one.
4485
                $row = Database::fetch_array($res);
4486
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
4487
                        VALUES
4488
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4489
                    "'".$row['type']."','".$row['category']."',".
4490
                    "'$value','".$row['title']."',".
4491
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4492
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
4493
                Database::query($insert);
4494
            } else {
4495
                // Such a setting does not exist.
4496
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
4497
            }
4498
        } else {
4499
            // Other access url.
4500
            if (!empty($subvar)) {
4501
                $select .= " AND subkey = '$subvar'";
4502
            }
4503
            if (!empty($cat)) {
4504
                $select .= " AND category = '$cat'";
4505
            }
4506
            $res = Database::query($select);
4507
4508
            if (Database::num_rows($res) > 0) {
4509
                // We have a setting for access_url 1, but none for the current one, so create one.
4510
                $row = Database::fetch_array($res);
4511
                if (1 == $row['access_url_changeable']) {
4512
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
4513
                            ('".$row['variable']."',".
4514
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4515
                        "'".$row['type']."','".$row['category']."',".
4516
                        "'$value','".$row['title']."',".
4517
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
4518
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4519
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
4520
                    Database::query($insert);
4521
                }
4522
            } else { // Such a setting does not exist.
4523
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
4524
            }
4525
        }
4526
    }
4527
}
4528
4529
/**
4530
 * Sets a whole category of settings to one specific value.
4531
 *
4532
 * @param string    Category
4533
 * @param string    Value
4534
 * @param int       Access URL. Optional. Defaults to 1
4535
 * @param array     Optional array of filters on field type
4536
 * @param string $category
4537
 * @param string $value
4538
 *
4539
 * @return bool
4540
 */
4541
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
4542
{
4543
    if (empty($category)) {
4544
        return false;
4545
    }
4546
    $category = Database::escape_string($category);
4547
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4548
    $access_url = (int) $access_url;
4549
    if (empty($access_url)) {
4550
        $access_url = 1;
4551
    }
4552
    if (isset($value)) {
4553
        $value = Database::escape_string($value);
4554
        $sql = "UPDATE $t_s SET selected_value = '$value'
4555
                WHERE category = '$category' AND access_url = $access_url";
4556
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4557
            $sql .= " AND ( ";
4558
            $i = 0;
4559
            foreach ($fieldtype as $type) {
4560
                if ($i > 0) {
4561
                    $sql .= ' OR ';
4562
                }
4563
                $type = Database::escape_string($type);
4564
                $sql .= " type='".$type."' ";
4565
                $i++;
4566
            }
4567
            $sql .= ")";
4568
        }
4569
        $res = Database::query($sql);
4570
4571
        return false !== $res;
4572
    } else {
4573
        $sql = "UPDATE $t_s SET selected_value = NULL
4574
                WHERE category = '$category' AND access_url = $access_url";
4575
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4576
            $sql .= " AND ( ";
4577
            $i = 0;
4578
            foreach ($fieldtype as $type) {
4579
                if ($i > 0) {
4580
                    $sql .= ' OR ';
4581
                }
4582
                $type = Database::escape_string($type);
4583
                $sql .= " type='".$type."' ";
4584
                $i++;
4585
            }
4586
            $sql .= ")";
4587
        }
4588
        $res = Database::query($sql);
4589
4590
        return false !== $res;
4591
    }
4592
}
4593
4594
/**
4595
 * Gets all available access urls in an array (as in the database).
4596
 *
4597
 * @return array An array of database records
4598
 */
4599
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
4600
{
4601
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4602
    $from = (int) $from;
4603
    $to = (int) $to;
4604
    $order = Database::escape_string($order);
4605
    $direction = Database::escape_string($direction);
4606
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
4607
    $sql = "SELECT id, url, description, active, created_by, tms
4608
            FROM $table
4609
            ORDER BY `$order` $direction
4610
            LIMIT $to OFFSET $from";
4611
    $res = Database::query($sql);
4612
4613
    return Database::store_result($res);
4614
}
4615
4616
/**
4617
 * Gets the access url info in an array.
4618
 *
4619
 * @param int  $id            Id of the access url
4620
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
4621
 *
4622
 * @return array All the info (url, description, active, created_by, tms)
4623
 *               from the access_url table
4624
 *
4625
 * @author Julio Montoya
4626
 */
4627
function api_get_access_url($id, $returnDefault = true)
4628
{
4629
    static $staticResult;
4630
    $id = (int) $id;
4631
4632
    if (isset($staticResult[$id])) {
4633
        $result = $staticResult[$id];
4634
    } else {
4635
        // Calling the Database:: library dont work this is handmade.
4636
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4637
        $sql = "SELECT url, description, active, created_by, tms
4638
                FROM $table_access_url WHERE id = '$id' ";
4639
        $res = Database::query($sql);
4640
        $result = @Database::fetch_array($res);
4641
        $staticResult[$id] = $result;
4642
    }
4643
4644
    // If the result url is 'http://localhost/' (the default) and the root_web
4645
    // (=current url) is different, and the $id is = 1 (which might mean
4646
    // api_get_current_access_url_id() returned 1 by default), then return the
4647
    // root_web setting instead of the current URL
4648
    // This is provided as an option to avoid breaking the storage of URL-specific
4649
    // homepages in home/localhost/
4650
    if (1 === $id && false === $returnDefault) {
4651
        $currentUrl = api_get_current_access_url_id();
4652
        // only do this if we are on the main URL (=1), otherwise we could get
4653
        // information on another URL instead of the one asked as parameter
4654
        if (1 === $currentUrl) {
4655
            $rootWeb = api_get_path(WEB_PATH);
4656
            $default = AccessUrl::DEFAULT_ACCESS_URL;
4657
            if ($result['url'] === $default && $rootWeb != $default) {
4658
                $result['url'] = $rootWeb;
4659
            }
4660
        }
4661
    }
4662
4663
    return $result;
4664
}
4665
4666
/**
4667
 * Gets all the current settings for a specific access url.
4668
 *
4669
 * @param string    The category, if any, that we want to get
4670
 * @param string    Whether we want a simple list (display a category) or
4671
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
4672
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
4673
 *
4674
 * @return array Array of database results for the current settings of the current access URL
4675
 */
4676
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
4677
{
4678
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4679
    $access_url = (int) $access_url;
4680
    $where_condition = '';
4681
    if (1 == $url_changeable) {
4682
        $where_condition = " AND access_url_changeable= '1' ";
4683
    }
4684
    if (empty($access_url) || -1 == $access_url) {
4685
        $access_url = 1;
4686
    }
4687
    $sql = "SELECT * FROM $table
4688
            WHERE access_url = $access_url  $where_condition ";
4689
4690
    if (!empty($cat)) {
4691
        $cat = Database::escape_string($cat);
4692
        $sql .= " AND category='$cat' ";
4693
    }
4694
    if ('group' == $ordering) {
4695
        $sql .= " ORDER BY id ASC";
4696
    } else {
4697
        $sql .= " ORDER BY 1,2 ASC";
4698
    }
4699
    $result = Database::query($sql);
4700
    if (null === $result) {
4701
        return [];
4702
    }
4703
    $result = Database::store_result($result, 'ASSOC');
4704
4705
    return $result;
4706
}
4707
4708
/**
4709
 * @param string $value       The value we want to record
4710
 * @param string $variable    The variable name we want to insert
4711
 * @param string $subKey      The subkey for the variable we want to insert
4712
 * @param string $type        The type for the variable we want to insert
4713
 * @param string $category    The category for the variable we want to insert
4714
 * @param string $title       The title
4715
 * @param string $comment     The comment
4716
 * @param string $scope       The scope
4717
 * @param string $subKeyText  The subkey text
4718
 * @param int    $accessUrlId The access_url for which this parameter is valid
4719
 * @param int    $visibility  The changeability of this setting for non-master urls
4720
 *
4721
 * @return int The setting ID
4722
 */
4723
function api_add_setting(
4724
    $value,
4725
    $variable,
4726
    $subKey = '',
4727
    $type = 'textfield',
4728
    $category = '',
4729
    $title = '',
4730
    $comment = '',
4731
    $scope = '',
4732
    $subKeyText = '',
4733
    $accessUrlId = 1,
4734
    $visibility = 0
4735
) {
4736
    $em = Database::getManager();
4737
4738
    $settingRepo = $em->getRepository(SettingsCurrent::class);
4739
    $accessUrlId = (int) $accessUrlId ?: 1;
4740
4741
    if (is_array($value)) {
4742
        $value = serialize($value);
4743
    } else {
4744
        $value = trim($value);
4745
    }
4746
4747
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
4748
4749
    if (!empty($subKey)) {
4750
        $criteria['subkey'] = $subKey;
4751
    }
4752
4753
    // Check if this variable doesn't exist already
4754
    /** @var SettingsCurrent $setting */
4755
    $setting = $settingRepo->findOneBy($criteria);
4756
4757
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
4758
        $setting->setSelectedValue($value);
4759
4760
        $em->persist($setting);
4761
        $em->flush();
4762
4763
        return $setting->getId();
4764
    }
4765
4766
    // Item not found for this access_url, we have to check if the whole thing is missing
4767
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
4768
    $setting = new SettingsCurrent();
4769
    $url = api_get_url_entity();
4770
4771
    $setting
4772
        ->setVariable($variable)
4773
        ->setSelectedValue($value)
4774
        ->setType($type)
4775
        ->setCategory($category)
4776
        ->setSubkey($subKey)
4777
        ->setTitle($title)
4778
        ->setComment($comment)
4779
        ->setScope($scope)
4780
        ->setSubkeytext($subKeyText)
4781
        ->setUrl(api_get_url_entity())
4782
        ->setAccessUrlChangeable($visibility);
4783
4784
    $em->persist($setting);
4785
    $em->flush();
4786
4787
    return $setting->getId();
4788
}
4789
4790
/**
4791
 * Checks wether a user can or can't view the contents of a course.
4792
 *
4793
 * @deprecated use CourseManager::is_user_subscribed_in_course
4794
 *
4795
 * @param int $userid User id or NULL to get it from $_SESSION
4796
 * @param int $cid    course id to check whether the user is allowed
4797
 *
4798
 * @return bool
4799
 */
4800
function api_is_course_visible_for_user($userid = null, $cid = null)
4801
{
4802
    if (null === $userid) {
4803
        $userid = api_get_user_id();
4804
    }
4805
    if (empty($userid) || strval(intval($userid)) != $userid) {
4806
        if (api_is_anonymous()) {
4807
            $userid = api_get_anonymous_id();
4808
        } else {
4809
            return false;
4810
        }
4811
    }
4812
    $cid = Database::escape_string($cid);
4813
4814
    $courseInfo = api_get_course_info($cid);
4815
    $courseId = $courseInfo['real_id'];
4816
    $is_platformAdmin = api_is_platform_admin();
4817
4818
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
4819
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
4820
4821
    $sql = "SELECT
4822
                $course_cat_table.code AS category_code,
4823
                $course_table.visibility,
4824
                $course_table.code,
4825
                $course_cat_table.code
4826
            FROM $course_table
4827
            LEFT JOIN $course_cat_table
4828
                ON $course_table.category_id = $course_cat_table.id
4829
            WHERE
4830
                $course_table.code = '$cid'
4831
            LIMIT 1";
4832
4833
    $result = Database::query($sql);
4834
4835
    if (Database::num_rows($result) > 0) {
4836
        $visibility = Database::fetch_array($result);
4837
        $visibility = $visibility['visibility'];
4838
    } else {
4839
        $visibility = 0;
4840
    }
4841
    // Shortcut permissions in case the visibility is "open to the world".
4842
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
4843
        return true;
4844
    }
4845
4846
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4847
4848
    $sql = "SELECT
4849
                is_tutor, status
4850
            FROM $tbl_course_user
4851
            WHERE
4852
                user_id  = '$userid' AND
4853
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
4854
                c_id = $courseId
4855
            LIMIT 1";
4856
4857
    $result = Database::query($sql);
4858
4859
    if (Database::num_rows($result) > 0) {
4860
        // This user has got a recorded state for this course.
4861
        $cuData = Database::fetch_array($result);
4862
        $is_courseMember = true;
4863
        $is_courseAdmin = (1 == $cuData['status']);
4864
    }
4865
4866
    if (!$is_courseAdmin) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $is_courseAdmin does not seem to be defined for all execution paths leading up to this point.
Loading history...
4867
        // This user has no status related to this course.
4868
        // Is it the session coach or the session admin?
4869
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4870
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4871
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4872
4873
        $sql = "SELECT
4874
                    session.id_coach, session_admin_id, session.id
4875
                FROM
4876
                    $tbl_session as session
4877
                INNER JOIN $tbl_session_course
4878
                    ON session_rel_course.session_id = session.id
4879
                    AND session_rel_course.c_id = '$courseId'
4880
                LIMIT 1";
4881
4882
        $result = Database::query($sql);
4883
        $row = Database::store_result($result);
4884
4885
        if ($row[0]['id_coach'] == $userid) {
4886
            $is_courseMember = true;
4887
            $is_courseAdmin = false;
4888
        } elseif ($row[0]['session_admin_id'] == $userid) {
4889
            $is_courseMember = false;
4890
            $is_courseAdmin = false;
4891
        } else {
4892
            // Check if the current user is the course coach.
4893
            $sql = "SELECT 1
4894
                    FROM $tbl_session_course
4895
                    WHERE session_rel_course.c_id = '$courseId'
4896
                    AND session_rel_course.id_coach = '$userid'
4897
                    LIMIT 1";
4898
4899
            $result = Database::query($sql);
4900
4901
            //if ($row = Database::fetch_array($result)) {
4902
            if (Database::num_rows($result) > 0) {
4903
                $is_courseMember = true;
4904
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4905
4906
                $sql = "SELECT status FROM $tbl_user
4907
                        WHERE id = $userid
4908
                        LIMIT 1";
4909
4910
                $result = Database::query($sql);
4911
4912
                if (1 == Database::result($result, 0, 0)) {
4913
                    $is_courseAdmin = true;
4914
                } else {
4915
                    $is_courseAdmin = false;
4916
                }
4917
            } else {
4918
                // Check if the user is a student is this session.
4919
                $sql = "SELECT  id
4920
                        FROM $tbl_session_course_user
4921
                        WHERE
4922
                            user_id  = '$userid' AND
4923
                            c_id = '$courseId'
4924
                        LIMIT 1";
4925
4926
                if (Database::num_rows($result) > 0) {
4927
                    // This user haa got a recorded state for this course.
4928
                    while ($row = Database::fetch_array($result)) {
4929
                        $is_courseMember = true;
4930
                        $is_courseAdmin = false;
4931
                    }
4932
                }
4933
            }
4934
        }
4935
    }
4936
4937
    switch ($visibility) {
4938
        case Course::OPEN_WORLD:
4939
            return true;
4940
        case Course::OPEN_PLATFORM:
4941
            return isset($userid);
4942
        case Course::REGISTERED:
4943
        case Course::CLOSED:
4944
            return $is_platformAdmin || $is_courseMember || $is_courseAdmin;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $is_courseMember does not seem to be defined for all execution paths leading up to this point.
Loading history...
4945
        case Course::HIDDEN:
4946
            return $is_platformAdmin;
4947
    }
4948
4949
    return false;
4950
}
4951
4952
/**
4953
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
4954
 *
4955
 * @param string the tool of the element
4956
 * @param int the element id in database
4957
 * @param int the session_id to compare with element session id
4958
 *
4959
 * @return bool true if the element is in the session, false else
4960
 */
4961
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
4962
{
4963
    if (is_null($session_id)) {
4964
        $session_id = api_get_session_id();
4965
    }
4966
4967
    $element_id = (int) $element_id;
4968
4969
    if (empty($element_id)) {
4970
        return false;
4971
    }
4972
4973
    // Get information to build query depending of the tool.
4974
    switch ($tool) {
4975
        case TOOL_SURVEY:
4976
            $table_tool = Database::get_course_table(TABLE_SURVEY);
4977
            $key_field = 'survey_id';
4978
            break;
4979
        case TOOL_ANNOUNCEMENT:
4980
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
4981
            $key_field = 'id';
4982
            break;
4983
        case TOOL_AGENDA:
4984
            $table_tool = Database::get_course_table(TABLE_AGENDA);
4985
            $key_field = 'id';
4986
            break;
4987
        case TOOL_GROUP:
4988
            $table_tool = Database::get_course_table(TABLE_GROUP);
4989
            $key_field = 'id';
4990
            break;
4991
        default:
4992
            return false;
4993
    }
4994
    $course_id = api_get_course_int_id();
4995
4996
    $sql = "SELECT session_id FROM $table_tool
4997
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
4998
    $rs = Database::query($sql);
4999
    if ($element_session_id = Database::result($rs, 0, 0)) {
5000
        if ($element_session_id == intval($session_id)) {
5001
            // The element belongs to the session.
5002
            return true;
5003
        }
5004
    }
5005
5006
    return false;
5007
}
5008
5009
/**
5010
 * Replaces "forbidden" characters in a filename string.
5011
 *
5012
 * @param string $filename
5013
 * @param bool   $treat_spaces_as_hyphens
5014
 *
5015
 * @return string
5016
 */
5017
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5018
{
5019
    // Some non-properly encoded file names can cause the whole file to be
5020
    // skipped when uploaded. Avoid this by detecting the encoding and
5021
    // converting to UTF-8, setting the source as ASCII (a reasonably
5022
    // limited characters set) if nothing could be found (BT#
5023
    $encoding = api_detect_encoding($filename);
5024
    if (empty($encoding)) {
5025
        $encoding = 'ASCII';
5026
        if (!api_is_valid_ascii($filename)) {
5027
            // try iconv and try non standard ASCII a.k.a CP437
5028
            // see BT#15022
5029
            if (function_exists('iconv')) {
5030
                $result = iconv('CP437', 'UTF-8', $filename);
5031
                if (api_is_valid_utf8($result)) {
5032
                    $filename = $result;
5033
                    $encoding = 'UTF-8';
5034
                }
5035
            }
5036
        }
5037
    }
5038
5039
    $filename = api_to_system_encoding($filename, $encoding);
5040
5041
    $url = URLify::filter(
5042
        $filename,
5043
        250,
5044
        '',
5045
        true,
5046
        false,
5047
        false,
5048
        false,
5049
        $treat_spaces_as_hyphens
5050
    );
5051
5052
    // Replace multiple dots at the end.
5053
    $regex = "/\.+$/";
5054
5055
    return preg_replace($regex, '', $url);
5056
}
5057
5058
/**
5059
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5060
 *
5061
 * @author Ivan Tcholakov, 28-JUN-2006.
5062
 */
5063
function api_request_uri()
5064
{
5065
    if (!empty($_SERVER['REQUEST_URI'])) {
5066
        return $_SERVER['REQUEST_URI'];
5067
    }
5068
    $uri = $_SERVER['SCRIPT_NAME'];
5069
    if (!empty($_SERVER['QUERY_STRING'])) {
5070
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5071
    }
5072
    $_SERVER['REQUEST_URI'] = $uri;
5073
5074
    return $uri;
5075
}
5076
5077
/** Gets the current access_url id of the Chamilo Platform.
5078
 * @author Julio Montoya <[email protected]>
5079
 *
5080
 * @return int access_url_id of the current Chamilo Installation
5081
 */
5082
function api_get_current_access_url_id()
5083
{
5084
    if (false === api_get_multiple_access_url()) {
5085
        return 1;
5086
    }
5087
5088
    static $id;
5089
    if (!empty($id)) {
5090
        return $id;
5091
    }
5092
5093
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5094
    $path = Database::escape_string(api_get_path(WEB_PATH));
5095
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5096
    $result = Database::query($sql);
5097
    if (Database::num_rows($result) > 0) {
5098
        $id = Database::result($result, 0, 0);
5099
        if (false === $id) {
5100
            return -1;
5101
        }
5102
5103
        return (int) $id;
5104
    }
5105
5106
    $id = 1;
5107
5108
    //if the url in WEB_PATH was not found, it can only mean that there is
5109
    // either a configuration problem or the first URL has not been defined yet
5110
    // (by default it is http://localhost/). Thus the more sensible thing we can
5111
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5112
    return 1;
5113
}
5114
5115
/**
5116
 * Gets the registered urls from a given user id.
5117
 *
5118
 * @author Julio Montoya <[email protected]>
5119
 *
5120
 * @param int $user_id
5121
 *
5122
 * @return array
5123
 */
5124
function api_get_access_url_from_user($user_id)
5125
{
5126
    $user_id = (int) $user_id;
5127
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5128
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5129
    $sql = "SELECT access_url_id
5130
            FROM $table_url_rel_user url_rel_user
5131
            INNER JOIN $table_url u
5132
            ON (url_rel_user.access_url_id = u.id)
5133
            WHERE user_id = ".$user_id;
5134
    $result = Database::query($sql);
5135
    $list = [];
5136
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5137
        $list[] = $row['access_url_id'];
5138
    }
5139
5140
    return $list;
5141
}
5142
5143
/**
5144
 * Checks whether the curent user is in a group or not.
5145
 *
5146
 * @param string        The group id - optional (takes it from session if not given)
5147
 * @param string        The course code - optional (no additional check by course if course code is not given)
5148
 *
5149
 * @return bool
5150
 *
5151
 * @author Ivan Tcholakov
5152
 */
5153
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5154
{
5155
    if (!empty($courseCodeParam)) {
5156
        $courseCode = api_get_course_id();
5157
        if (!empty($courseCode)) {
5158
            if ($courseCodeParam != $courseCode) {
5159
                return false;
5160
            }
5161
        } else {
5162
            return false;
5163
        }
5164
    }
5165
5166
    $groupId = api_get_group_id();
5167
5168
    if (isset($groupId) && '' != $groupId) {
5169
        if (!empty($groupIdParam)) {
5170
            return $groupIdParam == $groupId;
5171
        } else {
5172
            return true;
5173
        }
5174
    }
5175
5176
    return false;
5177
}
5178
5179
/**
5180
 * Checks whether a secret key is valid.
5181
 *
5182
 * @param string $original_key_secret - secret key from (webservice) client
5183
 * @param string $security_key        - security key from Chamilo
5184
 *
5185
 * @return bool - true if secret key is valid, false otherwise
5186
 */
5187
function api_is_valid_secret_key($original_key_secret, $security_key)
5188
{
5189
    if (empty($original_key_secret) || empty($security_key)) {
5190
        return false;
5191
    }
5192
5193
    return (string) $original_key_secret === sha1($security_key);
5194
}
5195
5196
/**
5197
 * Checks whether the server's operating system is Windows (TM).
5198
 *
5199
 * @return bool - true if the operating system is Windows, false otherwise
5200
 */
5201
function api_is_windows_os()
5202
{
5203
    if (function_exists('php_uname')) {
5204
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5205
        // We expect that this function will always work for Chamilo 1.8.x.
5206
        $os = php_uname();
5207
    }
5208
    // The following methods are not needed, but let them stay, just in case.
5209
    elseif (isset($_ENV['OS'])) {
5210
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5211
        $os = $_ENV['OS'];
5212
    } elseif (defined('PHP_OS')) {
5213
        // PHP_OS means on which OS PHP was compiled, this is why
5214
        // using PHP_OS is the last choice for detection.
5215
        $os = PHP_OS;
5216
    } else {
5217
        return false;
5218
    }
5219
5220
    return 'win' == strtolower(substr((string) $os, 0, 3));
5221
}
5222
5223
/**
5224
 * This function informs whether the sent request is XMLHttpRequest.
5225
 */
5226
function api_is_xml_http_request()
5227
{
5228
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5229
}
5230
5231
/**
5232
 * Returns a list of Chamilo's tools or
5233
 * checks whether a given identificator is a valid Chamilo's tool.
5234
 *
5235
 * @author Isaac flores paz
5236
 *
5237
 * @param string The tool name to filter
5238
 *
5239
 * @return mixed Filtered string or array
5240
 */
5241
function api_get_tools_lists($my_tool = null)
5242
{
5243
    $tools_list = [
5244
        TOOL_DOCUMENT,
5245
        TOOL_THUMBNAIL,
5246
        TOOL_HOTPOTATOES,
5247
        TOOL_CALENDAR_EVENT,
5248
        TOOL_LINK,
5249
        TOOL_COURSE_DESCRIPTION,
5250
        TOOL_SEARCH,
5251
        TOOL_LEARNPATH,
5252
        TOOL_ANNOUNCEMENT,
5253
        TOOL_FORUM,
5254
        TOOL_THREAD,
5255
        TOOL_POST,
5256
        TOOL_DROPBOX,
5257
        TOOL_QUIZ,
5258
        TOOL_USER,
5259
        TOOL_GROUP,
5260
        TOOL_BLOGS,
5261
        TOOL_CHAT,
5262
        TOOL_STUDENTPUBLICATION,
5263
        TOOL_TRACKING,
5264
        TOOL_HOMEPAGE_LINK,
5265
        TOOL_COURSE_SETTING,
5266
        TOOL_BACKUP,
5267
        TOOL_COPY_COURSE_CONTENT,
5268
        TOOL_RECYCLE_COURSE,
5269
        TOOL_COURSE_HOMEPAGE,
5270
        TOOL_COURSE_RIGHTS_OVERVIEW,
5271
        TOOL_UPLOAD,
5272
        TOOL_COURSE_MAINTENANCE,
5273
        TOOL_SURVEY,
5274
        //TOOL_WIKI,
5275
        TOOL_GLOSSARY,
5276
        TOOL_GRADEBOOK,
5277
        TOOL_NOTEBOOK,
5278
        TOOL_ATTENDANCE,
5279
        TOOL_COURSE_PROGRESS,
5280
    ];
5281
    if (empty($my_tool)) {
5282
        return $tools_list;
5283
    }
5284
5285
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5286
}
5287
5288
/**
5289
 * Checks whether we already approved the last version term and condition.
5290
 *
5291
 * @param int user id
5292
 *
5293
 * @return bool true if we pass false otherwise
5294
 */
5295
function api_check_term_condition($userId)
5296
{
5297
    if ('true' === api_get_setting('allow_terms_conditions')) {
5298
        // Check if exists terms and conditions
5299
        if (0 == LegalManager::count()) {
5300
            return true;
5301
        }
5302
5303
        $extraFieldValue = new ExtraFieldValue('user');
5304
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5305
            $userId,
5306
            'legal_accept'
5307
        );
5308
5309
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5310
            $result = $data['value'];
5311
            $user_conditions = explode(':', $result);
5312
            $version = $user_conditions[0];
5313
            $langId = $user_conditions[1];
5314
            $realVersion = LegalManager::get_last_version($langId);
5315
5316
            return $version >= $realVersion;
5317
        }
5318
5319
        return false;
5320
    }
5321
5322
    return false;
5323
}
5324
5325
/**
5326
 * Gets all information of a tool into course.
5327
 *
5328
 * @param int The tool id
5329
 *
5330
 * @return array
5331
 */
5332
function api_get_tool_information_by_name($name)
5333
{
5334
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5335
    $course_id = api_get_course_int_id();
5336
5337
    $sql = "SELECT id FROM tool
5338
            WHERE name = '".Database::escape_string($name)."' ";
5339
    $rs = Database::query($sql);
5340
    $data = Database::fetch_array($rs);
5341
    if ($data) {
5342
        $tool = $data['id'];
5343
        $sql = "SELECT * FROM $t_tool
5344
                WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
5345
        $rs = Database::query($sql);
5346
5347
        return Database::fetch_array($rs, 'ASSOC');
5348
    }
5349
5350
    return [];
5351
}
5352
5353
/**
5354
 * Function used to protect a "global" admin script.
5355
 * The function blocks access when the user has no global platform admin rights.
5356
 * Global admins are the admins that are registered in the main.admin table
5357
 * AND the users who have access to the "principal" portal.
5358
 * That means that there is a record in the main.access_url_rel_user table
5359
 * with his user id and the access_url_id=1.
5360
 *
5361
 * @author Julio Montoya
5362
 *
5363
 * @param int $user_id
5364
 *
5365
 * @return bool
5366
 */
5367
function api_is_global_platform_admin($user_id = null)
5368
{
5369
    $user_id = (int) $user_id;
5370
    if (empty($user_id)) {
5371
        $user_id = api_get_user_id();
5372
    }
5373
    if (api_is_platform_admin_by_id($user_id)) {
5374
        $urlList = api_get_access_url_from_user($user_id);
5375
        // The admin is registered in the first "main" site with access_url_id = 1
5376
        if (in_array(1, $urlList)) {
5377
            return true;
5378
        }
5379
    }
5380
5381
    return false;
5382
}
5383
5384
/**
5385
 * @param int  $admin_id_to_check
5386
 * @param int  $my_user_id
5387
 * @param bool $allow_session_admin
5388
 *
5389
 * @return bool
5390
 */
5391
function api_global_admin_can_edit_admin(
5392
    $admin_id_to_check,
5393
    $my_user_id = null,
5394
    $allow_session_admin = false
5395
) {
5396
    if (empty($my_user_id)) {
5397
        $my_user_id = api_get_user_id();
5398
    }
5399
5400
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
5401
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
5402
5403
    if ($iam_a_global_admin) {
5404
        // Global admin can edit everything
5405
        return true;
5406
    } else {
5407
        // If i'm a simple admin
5408
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
5409
5410
        if ($allow_session_admin) {
5411
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
5412
        }
5413
5414
        if ($is_platform_admin) {
5415
            if ($user_is_global_admin) {
5416
                return false;
5417
            } else {
5418
                return true;
5419
            }
5420
        }
5421
    }
5422
5423
    return false;
5424
}
5425
5426
/**
5427
 * @param int  $admin_id_to_check
5428
 * @param int  $my_user_id
5429
 * @param bool $allow_session_admin
5430
 *
5431
 * @return bool|null
5432
 */
5433
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
5434
{
5435
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
5436
        return true;
5437
    } else {
5438
        api_not_allowed();
5439
    }
5440
}
5441
5442
/**
5443
 * Function used to protect a global admin script.
5444
 * The function blocks access when the user has no global platform admin rights.
5445
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
5446
 *
5447
 * @author Julio Montoya
5448
 */
5449
function api_protect_global_admin_script()
5450
{
5451
    if (!api_is_global_platform_admin()) {
5452
        api_not_allowed();
5453
5454
        return false;
5455
    }
5456
5457
    return true;
5458
}
5459
5460
/**
5461
 * Check browser support for specific file types or features
5462
 * This function checks if the user's browser supports a file format or given
5463
 * feature, or returns the current browser and major version when
5464
 * $format=check_browser. Only a limited number of formats and features are
5465
 * checked by this method. Make sure you check its definition first.
5466
 *
5467
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
5468
 *
5469
 * @deprecated
5470
 *
5471
 * @return bool or return text array if $format=check_browser
5472
 *
5473
 * @author Juan Carlos Raña Trabado
5474
 */
5475
function api_browser_support($format = '')
5476
{
5477
    return true;
5478
5479
    $browser = new Browser();
0 ignored issues
show
Unused Code introduced by
$browser = new Browser() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5480
    $current_browser = $browser->getBrowser();
5481
    $a_versiontemp = explode('.', $browser->getVersion());
5482
    $current_majorver = $a_versiontemp[0];
5483
5484
    static $result;
5485
5486
    if (isset($result[$format])) {
5487
        return $result[$format];
5488
    }
5489
5490
    // Native svg support
5491
    if ('svg' == $format) {
5492
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5493
            ('Firefox' == $current_browser && $current_majorver > 1) ||
5494
            ('Safari' == $current_browser && $current_majorver >= 4) ||
5495
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
5496
            ('Opera' == $current_browser && $current_majorver >= 9)
5497
        ) {
5498
            $result[$format] = true;
5499
5500
            return true;
5501
        } else {
5502
            $result[$format] = false;
5503
5504
            return false;
5505
        }
5506
    } elseif ('pdf' == $format) {
5507
        // native pdf support
5508
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
5509
            $result[$format] = true;
5510
5511
            return true;
5512
        } else {
5513
            $result[$format] = false;
5514
5515
            return false;
5516
        }
5517
    } elseif ('tif' == $format || 'tiff' == $format) {
5518
        //native tif support
5519
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5520
            $result[$format] = true;
5521
5522
            return true;
5523
        } else {
5524
            $result[$format] = false;
5525
5526
            return false;
5527
        }
5528
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
5529
        //native ogg, ogv,oga support
5530
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
5531
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
5532
            ('Opera' == $current_browser && $current_majorver >= 9)) {
5533
            $result[$format] = true;
5534
5535
            return true;
5536
        } else {
5537
            $result[$format] = false;
5538
5539
            return false;
5540
        }
5541
    } elseif ('mpg' == $format || 'mpeg' == $format) {
5542
        //native mpg support
5543
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
5544
            $result[$format] = true;
5545
5546
            return true;
5547
        } else {
5548
            $result[$format] = false;
5549
5550
            return false;
5551
        }
5552
    } elseif ('mp4' == $format) {
5553
        //native mp4 support (TODO: Android, iPhone)
5554
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
5555
            $result[$format] = true;
5556
5557
            return true;
5558
        } else {
5559
            $result[$format] = false;
5560
5561
            return false;
5562
        }
5563
    } elseif ('mov' == $format) {
5564
        //native mov support( TODO:check iPhone)
5565
        if ('Safari' == $current_browser && $current_majorver >= 5 || 'iPhone' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Safari' == $current_br...ne' == $current_browser, Probably Intended Meaning: 'Safari' == $current_bro...e' == $current_browser)
Loading history...
5566
            $result[$format] = true;
5567
5568
            return true;
5569
        } else {
5570
            $result[$format] = false;
5571
5572
            return false;
5573
        }
5574
    } elseif ('avi' == $format) {
5575
        //native avi support
5576
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5577
            $result[$format] = true;
5578
5579
            return true;
5580
        } else {
5581
            $result[$format] = false;
5582
5583
            return false;
5584
        }
5585
    } elseif ('wmv' == $format) {
5586
        //native wmv support
5587
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5588
            $result[$format] = true;
5589
5590
            return true;
5591
        } else {
5592
            $result[$format] = false;
5593
5594
            return false;
5595
        }
5596
    } elseif ('webm' == $format) {
5597
        //native webm support (TODO:check IE9, Chrome9, Android)
5598
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5599
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5600
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5601
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
5602
            'Android' == $current_browser
5603
        ) {
5604
            $result[$format] = true;
5605
5606
            return true;
5607
        } else {
5608
            $result[$format] = false;
5609
5610
            return false;
5611
        }
5612
    } elseif ('wav' == $format) {
5613
        //native wav support (only some codecs !)
5614
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5615
            ('Safari' == $current_browser && $current_majorver >= 5) ||
5616
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5617
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5618
            ('Chrome' == $current_browser && $current_majorver > 9) ||
5619
            'Android' == $current_browser ||
5620
            'iPhone' == $current_browser
5621
        ) {
5622
            $result[$format] = true;
5623
5624
            return true;
5625
        } else {
5626
            $result[$format] = false;
5627
5628
            return false;
5629
        }
5630
    } elseif ('mid' == $format || 'kar' == $format) {
5631
        //native midi support (TODO:check Android)
5632
        if ('Opera' == $current_browser && $current_majorver >= 9 || 'Android' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Opera' == $current_bro...id' == $current_browser, Probably Intended Meaning: 'Opera' == $current_brow...d' == $current_browser)
Loading history...
5633
            $result[$format] = true;
5634
5635
            return true;
5636
        } else {
5637
            $result[$format] = false;
5638
5639
            return false;
5640
        }
5641
    } elseif ('wma' == $format) {
5642
        //native wma support
5643
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5644
            $result[$format] = true;
5645
5646
            return true;
5647
        } else {
5648
            $result[$format] = false;
5649
5650
            return false;
5651
        }
5652
    } elseif ('au' == $format) {
5653
        //native au support
5654
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5655
            $result[$format] = true;
5656
5657
            return true;
5658
        } else {
5659
            $result[$format] = false;
5660
5661
            return false;
5662
        }
5663
    } elseif ('mp3' == $format) {
5664
        //native mp3 support (TODO:check Android, iPhone)
5665
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
5666
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
5667
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5668
            'Android' == $current_browser ||
5669
            'iPhone' == $current_browser ||
5670
            'Firefox' == $current_browser
5671
        ) {
5672
            $result[$format] = true;
5673
5674
            return true;
5675
        } else {
5676
            $result[$format] = false;
5677
5678
            return false;
5679
        }
5680
    } elseif ('autocapitalize' == $format) {
5681
        // Help avoiding showing the autocapitalize option if the browser doesn't
5682
        // support it: this attribute is against the HTML5 standard
5683
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
5684
            return true;
5685
        } else {
5686
            return false;
5687
        }
5688
    } elseif ("check_browser" == $format) {
5689
        $array_check_browser = [$current_browser, $current_majorver];
5690
5691
        return $array_check_browser;
5692
    } else {
5693
        $result[$format] = false;
5694
5695
        return false;
5696
    }
5697
}
5698
5699
/**
5700
 * This function checks if exist path and file browscap.ini
5701
 * In order for this to work, your browscap configuration setting in php.ini
5702
 * must point to the correct location of the browscap.ini file on your system
5703
 * http://php.net/manual/en/function.get-browser.php.
5704
 *
5705
 * @return bool
5706
 *
5707
 * @author Juan Carlos Raña Trabado
5708
 */
5709
function api_check_browscap()
5710
{
5711
    $setting = ini_get('browscap');
5712
    if ($setting) {
5713
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
5714
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
5715
            return true;
5716
        }
5717
    }
5718
5719
    return false;
5720
}
5721
5722
/**
5723
 * Returns the <script> HTML tag.
5724
 */
5725
function api_get_js($file)
5726
{
5727
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
5728
}
5729
5730
function api_get_build_js($file)
5731
{
5732
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
5733
}
5734
5735
function api_get_build_css($file, $media = 'screen')
5736
{
5737
    return '<link
5738
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5739
}
5740
5741
/**
5742
 * Returns the <script> HTML tag.
5743
 *
5744
 * @return string
5745
 */
5746
function api_get_asset($file)
5747
{
5748
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
5749
}
5750
5751
/**
5752
 * Returns the <script> HTML tag.
5753
 *
5754
 * @param string $file
5755
 * @param string $media
5756
 *
5757
 * @return string
5758
 */
5759
function api_get_css_asset($file, $media = 'screen')
5760
{
5761
    return '<link
5762
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"
5763
        rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5764
}
5765
5766
/**
5767
 * Returns the <link> HTML tag.
5768
 *
5769
 * @param string $file
5770
 * @param string $media
5771
 */
5772
function api_get_css($file, $media = 'screen')
5773
{
5774
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5775
}
5776
5777
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false, $returnFileLocation = false)
5778
{
5779
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
5780
5781
    if ($returnOnlyPath) {
5782
        if ($returnFileLocation) {
5783
            return api_get_path(SYS_PUBLIC_PATH).'build/css/bootstrap.css';
5784
        }
5785
5786
        return $url;
5787
    }
5788
5789
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
5790
}
5791
5792
/**
5793
 * Returns the js header to include the jquery library.
5794
 */
5795
function api_get_jquery_js()
5796
{
5797
    return api_get_asset('jquery/jquery.min.js');
5798
}
5799
5800
/**
5801
 * Returns the jquery path.
5802
 *
5803
 * @return string
5804
 */
5805
function api_get_jquery_web_path()
5806
{
5807
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
5808
}
5809
5810
/**
5811
 * @return string
5812
 */
5813
function api_get_jquery_ui_js_web_path()
5814
{
5815
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
5816
}
5817
5818
/**
5819
 * @return string
5820
 */
5821
function api_get_jquery_ui_css_web_path()
5822
{
5823
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
5824
}
5825
5826
/**
5827
 * Returns the jquery-ui library js headers.
5828
 *
5829
 * @return string html tags
5830
 */
5831
function api_get_jquery_ui_js()
5832
{
5833
    $libraries = [];
5834
5835
    return api_get_jquery_libraries_js($libraries);
5836
}
5837
5838
function api_get_jqgrid_js()
5839
{
5840
    return api_get_build_css('free-jqgrid.css').PHP_EOL
5841
        .api_get_build_js('free-jqgrid.js');
5842
}
5843
5844
/**
5845
 * Returns the jquery library js and css headers.
5846
 *
5847
 * @param   array   list of jquery libraries supported jquery-ui
5848
 * @param   bool    add the jquery library
5849
 *
5850
 * @return string html tags
5851
 */
5852
function api_get_jquery_libraries_js($libraries)
5853
{
5854
    $js = '';
5855
5856
    //Document multiple upload funcionality
5857
    if (in_array('jquery-uploadzs', $libraries)) {
5858
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
5859
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
5860
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
5861
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
5862
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
5863
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
5864
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
5865
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
5866
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
5867
5868
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
5869
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
5870
    }
5871
5872
    // jquery datepicker
5873
    if (in_array('datepicker', $libraries)) {
5874
        $languaje = 'en-GB';
5875
        $platform_isocode = strtolower(api_get_language_isocode());
5876
5877
        $datapicker_langs = [
5878
            'af', 'ar', 'ar-DZ', 'az', 'bg', 'bs', 'ca', 'cs', 'cy-GB', 'da', 'de', 'el', 'en-AU', 'en-GB', 'en-NZ', 'eo', 'es', 'et', 'eu', 'fa', 'fi', 'fo', 'fr', 'fr-CH', 'gl', 'he', 'hi', 'hr', 'hu', 'hy', 'id', 'is', 'it', 'ja', 'ka', 'kk', 'km', 'ko', 'lb', 'lt', 'lv', 'mk', 'ml', 'ms', 'nl', 'nl-BE', 'no', 'pl', 'pt', 'pt-BR', 'rm', 'ro', 'ru', 'sk', 'sl', 'sq', 'sr', 'sr-SR', 'sv', 'ta', 'th', 'tj', 'tr', 'uk', 'vi', 'zh-CN', 'zh-HK', 'zh-TW',
5879
        ];
5880
        if (in_array($platform_isocode, $datapicker_langs)) {
5881
            $languaje = $platform_isocode;
5882
        }
5883
5884
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
5885
        $script = '<script>
5886
        $(function(){
5887
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
5888
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
5889
        });
5890
        </script>
5891
        ';
5892
        $js .= $script;
5893
    }
5894
5895
    return $js;
5896
}
5897
5898
/**
5899
 * Returns the URL to the course or session, removing the complexity of the URL
5900
 * building piece by piece.
5901
 *
5902
 * This function relies on api_get_course_info()
5903
 *
5904
 * @param int $courseId  The course code - optional (takes it from context if not given)
5905
 * @param int $sessionId The session ID  - optional (takes it from context if not given)
5906
 * @param int $groupId   The group ID - optional (takes it from context if not given)
5907
 *
5908
 * @return string The URL to a course, a session, or empty string if nothing works
5909
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
5910
 *
5911
 * @author  Julio Montoya
5912
 */
5913
function api_get_course_url($courseId = null, $sessionId = null, $groupId = null)
5914
{
5915
    $url = '';
5916
    // If courseCode not set, get context or []
5917
    if (empty($courseId)) {
5918
        $courseId = api_get_course_int_id();
5919
    }
5920
5921
    // If sessionId not set, get context or 0
5922
    if (empty($sessionId)) {
5923
        $sessionId = api_get_session_id();
5924
    }
5925
5926
    // If groupId not set, get context or 0
5927
    if (empty($groupId)) {
5928
        $groupId = api_get_group_id();
5929
    }
5930
5931
    // Build the URL
5932
    if (!empty($courseId)) {
5933
        $webCourseHome = '/course/'.$courseId.'/home';
5934
        // directory not empty, so we do have a course
5935
        $url = $webCourseHome.'?sid='.$sessionId.'&gid='.$groupId;
5936
    } else {
5937
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
5938
            // if the course was unset and the session was set, send directly to the session
5939
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
5940
        }
5941
    }
5942
5943
    // if not valid combination was found, return an empty string
5944
    return $url;
5945
}
5946
5947
/**
5948
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
5949
 */
5950
function api_get_multiple_access_url(): bool
5951
{
5952
    global $_configuration;
5953
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
5954
        return true;
5955
    }
5956
5957
    return false;
5958
}
5959
5960
function api_is_multiple_url_enabled(): bool
5961
{
5962
    return api_get_multiple_access_url();
5963
}
5964
5965
/**
5966
 * Returns a md5 unique id.
5967
 *
5968
 * @todo add more parameters
5969
 */
5970
function api_get_unique_id()
5971
{
5972
    return md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
5973
}
5974
5975
/**
5976
 * @param int Course id
5977
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
5978
 * @param int the item id (tool id, exercise id, lp id)
5979
 *
5980
 * @return bool
5981
 */
5982
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
5983
{
5984
    if (api_is_platform_admin()) {
5985
        return false;
5986
    }
5987
    if ('true' === api_get_setting('gradebook_locking_enabled')) {
5988
        if (empty($course_code)) {
5989
            $course_code = api_get_course_id();
5990
        }
5991
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
5992
        $item_id = (int) $item_id;
5993
        $link_type = (int) $link_type;
5994
        $course_code = Database::escape_string($course_code);
5995
        $sql = "SELECT locked FROM $table
5996
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
5997
        $result = Database::query($sql);
5998
        if (Database::num_rows($result)) {
5999
            return true;
6000
        }
6001
    }
6002
6003
    return false;
6004
}
6005
6006
/**
6007
 * Blocks a page if the item was added in a gradebook.
6008
 *
6009
 * @param int       exercise id, work id, thread id,
6010
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6011
 * see gradebook/lib/be/linkfactory
6012
 * @param string    course code
6013
 *
6014
 * @return false|null
6015
 */
6016
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6017
{
6018
    if (api_is_platform_admin()) {
6019
        return false;
6020
    }
6021
6022
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6023
        $message = Display::return_message(
6024
            get_lang(
6025
                'This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'
6026
            ),
6027
            'warning'
6028
        );
6029
        api_not_allowed(true, $message);
6030
    }
6031
}
6032
6033
/**
6034
 * Checks the PHP version installed is enough to run Chamilo.
6035
 *
6036
 * @param string Include path (used to load the error page)
6037
 */
6038
function api_check_php_version()
6039
{
6040
    if (!function_exists('version_compare') ||
6041
        version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')
6042
    ) {
6043
        throw new Exception('Wrong PHP version');
6044
    }
6045
}
6046
6047
/**
6048
 * Checks whether the Archive directory is present and writeable. If not,
6049
 * prints a warning message.
6050
 */
6051
function api_check_archive_dir()
6052
{
6053
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6054
        $message = Display::return_message(
6055
            get_lang(
6056
                'The var/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'
6057
            ),
6058
            'warning'
6059
        );
6060
        api_not_allowed(true, $message);
6061
    }
6062
}
6063
6064
/**
6065
 * Returns an array of global configuration settings which should be ignored
6066
 * when printing the configuration settings screens.
6067
 *
6068
 * @return array Array of strings, each identifying one of the excluded settings
6069
 */
6070
function api_get_locked_settings()
6071
{
6072
    return [
6073
        'permanently_remove_deleted_files',
6074
        'account_valid_duration',
6075
        'service_ppt2lp',
6076
        'wcag_anysurfer_public_pages',
6077
        'upload_extensions_list_type',
6078
        'upload_extensions_blacklist',
6079
        'upload_extensions_whitelist',
6080
        'upload_extensions_skip',
6081
        'upload_extensions_replace_by',
6082
        'hide_dltt_markup',
6083
        'split_users_upload_directory',
6084
        'permissions_for_new_directories',
6085
        'permissions_for_new_files',
6086
        'platform_charset',
6087
        'ldap_description',
6088
        'cas_activate',
6089
        'cas_server',
6090
        'cas_server_uri',
6091
        'cas_port',
6092
        'cas_protocol',
6093
        'cas_add_user_activate',
6094
        'update_user_info_cas_with_ldap',
6095
        'languagePriority1',
6096
        'languagePriority2',
6097
        'languagePriority3',
6098
        'languagePriority4',
6099
        'login_is_email',
6100
        'chamilo_database_version',
6101
    ];
6102
}
6103
6104
/**
6105
 * Guess the real ip for register in the database, even in reverse proxy cases.
6106
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6107
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6108
 * Note: the result of this function is not SQL-safe. Please escape it before
6109
 * inserting in a database.
6110
 *
6111
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6112
 *
6113
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6114
 *
6115
 * @version CEV CHANGE 24APR2012
6116
 */
6117
function api_get_real_ip()
6118
{
6119
    $ip = trim($_SERVER['REMOTE_ADDR']);
6120
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6121
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6122
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6123
        } else {
6124
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6125
        }
6126
        $ip = trim($ip1);
6127
    }
6128
6129
    return $ip;
6130
}
6131
6132
/**
6133
 * Checks whether an IP is included inside an IP range.
6134
 *
6135
 * @param string IP address
6136
 * @param string IP range
6137
 * @param string $ip
6138
 *
6139
 * @return bool True if IP is in the range, false otherwise
6140
 *
6141
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6142
 * @author Yannick Warnier for improvements and managment of multiple ranges
6143
 *
6144
 * @todo check for IPv6 support
6145
 */
6146
function api_check_ip_in_range($ip, $range)
6147
{
6148
    if (empty($ip) or empty($range)) {
6149
        return false;
6150
    }
6151
    $ip_ip = ip2long($ip);
6152
    // divide range param into array of elements
6153
    if (false !== strpos($range, ',')) {
6154
        $ranges = explode(',', $range);
6155
    } else {
6156
        $ranges = [$range];
6157
    }
6158
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6159
        $range = trim($range);
6160
        if (empty($range)) {
6161
            continue;
6162
        }
6163
        if (false === strpos($range, '/')) {
6164
            if (0 === strcmp($ip, $range)) {
6165
                return true; // there is a direct IP match, return OK
6166
            }
6167
            continue; //otherwise, get to the next range
6168
        }
6169
        // the range contains a "/", so analyse completely
6170
        [$net, $mask] = explode("/", $range);
6171
6172
        $ip_net = ip2long($net);
6173
        // mask binary magic
6174
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6175
6176
        $ip_ip_net = $ip_ip & $ip_mask;
6177
        if ($ip_ip_net == $ip_net) {
6178
            return true;
6179
        }
6180
    }
6181
6182
    return false;
6183
}
6184
6185
function api_check_user_access_to_legal($courseInfo)
6186
{
6187
    if (empty($courseInfo)) {
6188
        return false;
6189
    }
6190
6191
    $visibility = (int) $courseInfo['visibility'];
6192
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6193
6194
    return
6195
        in_array($visibility, $visibilityList) ||
6196
        api_is_drh() ||
6197
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
6198
}
6199
6200
/**
6201
 * Checks if the global chat is enabled or not.
6202
 *
6203
 * @return bool
6204
 */
6205
function api_is_global_chat_enabled()
6206
{
6207
    return
6208
        !api_is_anonymous() &&
6209
        'true' === api_get_setting('allow_global_chat') &&
6210
        'true' === api_get_setting('allow_social_tool');
6211
}
6212
6213
/**
6214
 * @param int   $item_id
6215
 * @param int   $tool_id
6216
 * @param int   $group_id   id
6217
 * @param array $courseInfo
6218
 * @param int   $sessionId
6219
 * @param int   $userId
6220
 *
6221
 * @deprecated
6222
 */
6223
function api_set_default_visibility(
6224
    $item_id,
6225
    $tool_id,
6226
    $group_id = 0,
6227
    $courseInfo = [],
6228
    $sessionId = 0,
6229
    $userId = 0
6230
) {
6231
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6232
    $courseId = $courseInfo['real_id'];
6233
    $courseCode = $courseInfo['code'];
6234
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6235
    $userId = empty($userId) ? api_get_user_id() : $userId;
6236
6237
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6238
    if (is_null($group_id)) {
6239
        $group_id = 0;
6240
    } else {
6241
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6242
    }
6243
6244
    $groupInfo = [];
6245
    if (!empty($group_id)) {
6246
        $groupInfo = GroupManager::get_group_properties($group_id);
6247
    }
6248
    $original_tool_id = $tool_id;
6249
6250
    switch ($tool_id) {
6251
        case TOOL_LINK:
6252
        case TOOL_LINK_CATEGORY:
6253
            $tool_id = 'links';
6254
            break;
6255
        case TOOL_DOCUMENT:
6256
            $tool_id = 'documents';
6257
            break;
6258
        case TOOL_LEARNPATH:
6259
            $tool_id = 'learning';
6260
            break;
6261
        case TOOL_ANNOUNCEMENT:
6262
            $tool_id = 'announcements';
6263
            break;
6264
        case TOOL_FORUM:
6265
        case TOOL_FORUM_CATEGORY:
6266
        case TOOL_FORUM_THREAD:
6267
            $tool_id = 'forums';
6268
            break;
6269
        case TOOL_QUIZ:
6270
            $tool_id = 'quiz';
6271
            break;
6272
    }
6273
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6274
6275
    if (isset($setting[$tool_id])) {
6276
        $visibility = 'invisible';
6277
        if ('true' === $setting[$tool_id]) {
6278
            $visibility = 'visible';
6279
        }
6280
6281
        // Read the portal and course default visibility
6282
        if ('documents' === $tool_id) {
6283
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6284
        }
6285
6286
        // Fixes default visibility for tests
6287
        switch ($original_tool_id) {
6288
            case TOOL_QUIZ:
6289
                if (empty($sessionId)) {
6290
                    $objExerciseTmp = new Exercise($courseId);
6291
                    $objExerciseTmp->read($item_id);
6292
                    if ('visible' === $visibility) {
6293
                        $objExerciseTmp->enable();
6294
                        $objExerciseTmp->save();
6295
                    } else {
6296
                        $objExerciseTmp->disable();
6297
                        $objExerciseTmp->save();
6298
                    }
6299
                }
6300
                break;
6301
        }
6302
    }
6303
}
6304
6305
function api_get_roles()
6306
{
6307
    $hierarchy = Container::$container->getParameter('security.role_hierarchy.roles');
0 ignored issues
show
Bug introduced by
The method getParameter() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

6307
    /** @scrutinizer ignore-call */ 
6308
    $hierarchy = Container::$container->getParameter('security.role_hierarchy.roles');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
6308
    $roles = [];
6309
    array_walk_recursive($hierarchy, function ($role) use (&$roles) {
6310
        $roles[$role] = $role;
6311
    });
6312
6313
    return $roles;
6314
}
6315
6316
/**
6317
 * @param string $file
6318
 *
6319
 * @return string
6320
 */
6321
function api_get_js_simple($file)
6322
{
6323
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
6324
}
6325
6326
/**
6327
 * Modify default memory_limit and max_execution_time limits
6328
 * Needed when processing long tasks.
6329
 */
6330
function api_set_more_memory_and_time_limits()
6331
{
6332
    if (function_exists('ini_set')) {
6333
        api_set_memory_limit('256M');
6334
        ini_set('max_execution_time', 1800);
6335
    }
6336
}
6337
6338
/**
6339
 * Tries to set memory limit, if authorized and new limit is higher than current.
6340
 *
6341
 * @param string $mem New memory limit
6342
 *
6343
 * @return bool True on success, false on failure or current is higher than suggested
6344
 * @assert (null) === false
6345
 * @assert (-1) === false
6346
 * @assert (0) === true
6347
 * @assert ('1G') === true
6348
 */
6349
function api_set_memory_limit($mem)
6350
{
6351
    //if ini_set() not available, this function is useless
6352
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
6353
        return false;
6354
    }
6355
6356
    $memory_limit = ini_get('memory_limit');
6357
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
6358
        ini_set('memory_limit', $mem);
6359
6360
        return true;
6361
    }
6362
6363
    return false;
6364
}
6365
6366
/**
6367
 * Gets memory limit in bytes.
6368
 *
6369
 * @param string The memory size (128M, 1G, 1000K, etc)
6370
 *
6371
 * @return int
6372
 * @assert (null) === false
6373
 * @assert ('1t')  === 1099511627776
6374
 * @assert ('1g')  === 1073741824
6375
 * @assert ('1m')  === 1048576
6376
 * @assert ('100k') === 102400
6377
 */
6378
function api_get_bytes_memory_limit($mem)
6379
{
6380
    $size = strtolower(substr($mem, -1));
6381
6382
    switch ($size) {
6383
        case 't':
6384
            $mem = (int) substr($mem, -1) * 1024 * 1024 * 1024 * 1024;
6385
            break;
6386
        case 'g':
6387
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024 * 1024;
6388
            break;
6389
        case 'm':
6390
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024;
6391
            break;
6392
        case 'k':
6393
            $mem = (int) substr($mem, 0, -1) * 1024;
6394
            break;
6395
        default:
6396
            // we assume it's integer only
6397
            $mem = (int) $mem;
6398
            break;
6399
    }
6400
6401
    return $mem;
6402
}
6403
6404
/**
6405
 * Finds all the information about a user from username instead of user id.
6406
 *
6407
 * @param string $officialCode
6408
 *
6409
 * @return array $user_info user_id, lastname, firstname, username, email, ...
6410
 *
6411
 * @author Yannick Warnier <[email protected]>
6412
 */
6413
function api_get_user_info_from_official_code($officialCode)
6414
{
6415
    if (empty($officialCode)) {
6416
        return false;
6417
    }
6418
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
6419
            WHERE official_code ='".Database::escape_string($officialCode)."'";
6420
    $result = Database::query($sql);
6421
    if (Database::num_rows($result) > 0) {
6422
        $result_array = Database::fetch_array($result);
6423
6424
        return _api_format_user($result_array);
6425
    }
6426
6427
    return false;
6428
}
6429
6430
/**
6431
 * @param string $usernameInputId
6432
 * @param string $passwordInputId
6433
 *
6434
 * @return string|null
6435
 */
6436
function api_get_password_checker_js($usernameInputId, $passwordInputId)
6437
{
6438
    $checkPass = api_get_setting('allow_strength_pass_checker');
6439
    $useStrengthPassChecker = 'true' === $checkPass;
6440
6441
    if (false === $useStrengthPassChecker) {
6442
        return null;
6443
    }
6444
6445
    $translations = [
6446
        'wordLength' => get_lang('The password is too short'),
6447
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
6448
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
6449
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
6450
        'wordRepetitions' => get_lang('Too many repetitions'),
6451
        'wordSequences' => get_lang('Your password contains sequences'),
6452
        'errorList' => get_lang('errors found'),
6453
        'veryWeak' => get_lang('Very weak'),
6454
        'weak' => get_lang('Weak'),
6455
        'normal' => get_lang('Normal'),
6456
        'medium' => get_lang('Medium'),
6457
        'strong' => get_lang('Strong'),
6458
        'veryStrong' => get_lang('Very strong'),
6459
    ];
6460
6461
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.js');
6462
    $js .= "<script>
6463
    var errorMessages = {
6464
        password_to_short : \"".get_lang('The password is too short')."\",
6465
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
6466
    };
6467
6468
    $(function() {
6469
        var lang = ".json_encode($translations).";
6470
        var options = {
6471
            onLoad : function () {
6472
                //$('#messages').text('Start typing password');
6473
            },
6474
            onKeyUp: function (evt) {
6475
                $(evt.target).pwstrength('outputErrorList');
6476
            },
6477
            errorMessages : errorMessages,
6478
            viewports: {
6479
                progress: '#password_progress',
6480
                verdict: '#password-verdict',
6481
                errors: '#password-errors'
6482
            },
6483
            usernameField: '$usernameInputId'
6484
        };
6485
        options.i18n = {
6486
            t: function (key) {
6487
                var result = lang[key];
6488
                return result === key ? '' : result; // This assumes you return the
6489
            }
6490
        };
6491
        $('".$passwordInputId."').pwstrength(options);
6492
    });
6493
    </script>";
6494
6495
    return $js;
6496
}
6497
6498
/**
6499
 * create an user extra field called 'captcha_blocked_until_date'.
6500
 *
6501
 * @param string $username
6502
 *
6503
 * @return bool
6504
 */
6505
function api_block_account_captcha($username)
6506
{
6507
    $userInfo = api_get_user_info_from_username($username);
6508
    if (empty($userInfo)) {
6509
        return false;
6510
    }
6511
    $minutesToBlock = api_get_setting('captcha_time_to_block');
6512
    $time = time() + $minutesToBlock * 60;
6513
    UserManager::update_extra_field_value(
6514
        $userInfo['user_id'],
6515
        'captcha_blocked_until_date',
6516
        api_get_utc_datetime($time)
6517
    );
6518
6519
    return true;
6520
}
6521
6522
/**
6523
 * @param string $username
6524
 *
6525
 * @return bool
6526
 */
6527
function api_clean_account_captcha($username)
6528
{
6529
    $userInfo = api_get_user_info_from_username($username);
6530
    if (empty($userInfo)) {
6531
        return false;
6532
    }
6533
    Session::erase('loginFailedCount');
6534
    UserManager::update_extra_field_value(
6535
        $userInfo['user_id'],
6536
        'captcha_blocked_until_date',
6537
        null
6538
    );
6539
6540
    return true;
6541
}
6542
6543
/**
6544
 * @param string $username
6545
 *
6546
 * @return bool
6547
 */
6548
function api_get_user_blocked_by_captcha($username)
6549
{
6550
    $userInfo = api_get_user_info_from_username($username);
6551
    if (empty($userInfo)) {
6552
        return false;
6553
    }
6554
    $data = UserManager::get_extra_user_data_by_field(
6555
        $userInfo['user_id'],
6556
        'captcha_blocked_until_date'
6557
    );
6558
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
6559
        return $data['captcha_blocked_until_date'];
6560
    }
6561
6562
    return false;
6563
}
6564
6565
/**
6566
 * If true, the drh can access all content (courses, users) inside a session.
6567
 *
6568
 * @return bool
6569
 */
6570
function api_drh_can_access_all_session_content()
6571
{
6572
    return 'true' === api_get_setting('drh_can_access_all_session_content');
6573
}
6574
6575
/**
6576
 * Checks if user can login as another user.
6577
 *
6578
 * @param int $loginAsUserId the user id to log in
6579
 * @param int $userId        my user id
6580
 *
6581
 * @return bool
6582
 */
6583
function api_can_login_as($loginAsUserId, $userId = null)
6584
{
6585
    $loginAsUserId = (int) $loginAsUserId;
6586
6587
    if (empty($loginAsUserId)) {
6588
        return false;
6589
    }
6590
6591
    if (empty($userId)) {
6592
        $userId = api_get_user_id();
6593
    }
6594
6595
    if ($loginAsUserId == $userId) {
6596
        return false;
6597
    }
6598
6599
    // Check if the user to login is an admin
6600
    if (api_is_platform_admin_by_id($loginAsUserId)) {
6601
        // Only super admins can login to admin accounts
6602
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
6603
            return false;
6604
        }
6605
    }
6606
6607
    $userInfo = api_get_user_info($loginAsUserId);
6608
6609
    $isDrh = function () use ($loginAsUserId) {
6610
        if (api_is_drh()) {
6611
            if (api_drh_can_access_all_session_content()) {
6612
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
6613
                    'drh_all',
6614
                    api_get_user_id()
6615
                );
6616
                $userList = [];
6617
                if (is_array($users)) {
6618
                    foreach ($users as $user) {
6619
                        $userList[] = $user['id'];
6620
                    }
6621
                }
6622
                if (in_array($loginAsUserId, $userList)) {
6623
                    return true;
6624
                }
6625
            } else {
6626
                if (api_is_drh() &&
6627
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
6628
                ) {
6629
                    return true;
6630
                }
6631
            }
6632
        }
6633
6634
        return false;
6635
    };
6636
6637
    $loginAsStatusForSessionAdmins = [STUDENT];
6638
6639
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
6640
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
6641
    }
6642
6643
    return api_is_platform_admin() ||
6644
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
6645
        $isDrh();
6646
}
6647
6648
/**
6649
 * @return bool
6650
 */
6651
function api_is_allowed_in_course()
6652
{
6653
    if (api_is_platform_admin()) {
6654
        return true;
6655
    }
6656
6657
    $user = api_get_current_user();
6658
    if ($user instanceof User) {
6659
        if ($user->hasRole('ROLE_CURRENT_COURSE_SESSION_STUDENT') ||
6660
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
6661
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
6662
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
6663
        ) {
6664
            return true;
6665
        }
6666
    }
6667
6668
    return false;
6669
}
6670
6671
/**
6672
 * Return true on https install.
6673
 *
6674
 * @return bool
6675
 */
6676
function api_is_https()
6677
{
6678
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! empty($_SERVER['HTTP_...ttps_forwarded_proto')), Probably Intended Meaning: ! empty($_SERVER['HTTP_X...tps_forwarded_proto')))
Loading history...
6679
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
6680
    ) {
6681
        $isSecured = true;
6682
    } else {
6683
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
6684
            $isSecured = true;
6685
        } else {
6686
            $isSecured = false;
6687
            // last chance
6688
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
6689
                $isSecured = true;
6690
            }
6691
        }
6692
    }
6693
6694
    return $isSecured;
6695
}
6696
6697
/**
6698
 * Return protocol (http or https).
6699
 *
6700
 * @return string
6701
 */
6702
function api_get_protocol()
6703
{
6704
    return api_is_https() ? 'https' : 'http';
6705
}
6706
6707
/**
6708
 * Get origin.
6709
 *
6710
 * @param string
6711
 *
6712
 * @return string
6713
 */
6714
function api_get_origin()
6715
{
6716
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
6717
}
6718
6719
/**
6720
 * Warns an user that the portal reach certain limit.
6721
 *
6722
 * @param string $limitName
6723
 */
6724
function api_warn_hosting_contact($limitName)
6725
{
6726
    $hostingParams = api_get_configuration_value(1);
6727
    $email = null;
6728
6729
    if (!empty($hostingParams)) {
6730
        if (isset($hostingParams['hosting_contact_mail'])) {
6731
            $email = $hostingParams['hosting_contact_mail'];
6732
        }
6733
    }
6734
6735
    if (!empty($email)) {
6736
        $subject = get_lang('Hosting warning reached');
6737
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
6738
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
6739
        if (isset($hostingParams[$limitName])) {
6740
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
6741
        }
6742
        api_mail_html(null, $email, $subject, $body);
6743
    }
6744
}
6745
6746
/**
6747
 * Gets value of a variable from config/configuration.php
6748
 * Variables that are not set in the configuration.php file but set elsewhere:
6749
 * - virtual_css_theme_folder (vchamilo plugin)
6750
 * - access_url (global.inc.php)
6751
 * - apc/apc_prefix (global.inc.php).
6752
 *
6753
 * @param string $variable
6754
 *
6755
 * @return bool|mixed
6756
 */
6757
function api_get_configuration_value($variable)
6758
{
6759
    global $_configuration;
6760
    // Check the current url id, id = 1 by default
6761
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
6762
6763
    $variable = trim($variable);
6764
6765
    // Check if variable exists
6766
    if (isset($_configuration[$variable])) {
6767
        if (is_array($_configuration[$variable])) {
6768
            // Check if it exists for the sub portal
6769
            if (array_key_exists($urlId, $_configuration[$variable])) {
6770
                return $_configuration[$variable][$urlId];
6771
            } else {
6772
                // Try to found element with id = 1 (master portal)
6773
                if (array_key_exists(1, $_configuration[$variable])) {
6774
                    return $_configuration[$variable][1];
6775
                }
6776
            }
6777
        }
6778
6779
        return $_configuration[$variable];
6780
    }
6781
6782
    return false;
6783
}
6784
6785
/**
6786
 * Retreives and returns a value in a hierarchical configuration array
6787
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
6788
 *
6789
 * @param string $path      the successive array keys, separated by the separator
6790
 * @param mixed  $default   value to be returned if not found, null by default
6791
 * @param string $separator '/' by default
6792
 * @param array  $array     the active configuration array by default
6793
 *
6794
 * @return mixed the found value or $default
6795
 */
6796
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
6797
{
6798
    $pos = strpos($path, $separator);
6799
    if (false === $pos) {
6800
        if (is_null($array)) {
6801
            return api_get_configuration_value($path);
6802
        }
6803
        if (is_array($array) && array_key_exists($path, $array)) {
6804
            return $array[$path];
6805
        }
6806
6807
        return $default;
6808
    }
6809
    $key = substr($path, 0, $pos);
6810
    if (is_null($array)) {
6811
        $newArray = api_get_configuration_value($key);
6812
    } elseif (is_array($array) && array_key_exists($key, $array)) {
6813
        $newArray = $array[$key];
6814
    } else {
6815
        return $default;
6816
    }
6817
    if (is_array($newArray)) {
6818
        $newPath = substr($path, $pos + 1);
6819
6820
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
6821
    }
6822
6823
    return $default;
6824
}
6825
6826
/**
6827
 * Retrieves and returns a value in a hierarchical configuration array
6828
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
6829
 *
6830
 * @param array  $array     the recursive array that contains the value to be returned (or not)
6831
 * @param string $path      the successive array keys, separated by the separator
6832
 * @param mixed  $default   the value to be returned if not found
6833
 * @param string $separator the separator substring
6834
 *
6835
 * @return mixed the found value or $default
6836
 */
6837
function api_array_sub_value($array, $path, $default = null, $separator = '/')
6838
{
6839
    $pos = strpos($path, $separator);
6840
    if (false === $pos) {
6841
        if (is_array($array) && array_key_exists($path, $array)) {
6842
            return $array[$path];
6843
        }
6844
6845
        return $default;
6846
    }
6847
    $key = substr($path, 0, $pos);
6848
    if (is_array($array) && array_key_exists($key, $array)) {
6849
        $newArray = $array[$key];
6850
    } else {
6851
        return $default;
6852
    }
6853
    if (is_array($newArray)) {
6854
        $newPath = substr($path, $pos + 1);
6855
6856
        return api_array_sub_value($newArray, $newPath, $default);
6857
    }
6858
6859
    return $default;
6860
}
6861
6862
/**
6863
 * Returns supported image extensions in the portal.
6864
 *
6865
 * @param bool $supportVectors Whether vector images should also be accepted or not
6866
 *
6867
 * @return array Supported image extensions in the portal
6868
 */
6869
function api_get_supported_image_extensions($supportVectors = true)
6870
{
6871
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
6872
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
6873
    if ($supportVectors) {
6874
        array_push($supportedImageExtensions, 'svg');
6875
    }
6876
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
6877
        array_push($supportedImageExtensions, 'webp');
6878
    }
6879
6880
    return $supportedImageExtensions;
6881
}
6882
6883
/**
6884
 * This setting changes the registration status for the campus.
6885
 *
6886
 * @author Patrick Cool <[email protected]>, Ghent University
6887
 *
6888
 * @version August 2006
6889
 *
6890
 * @param bool $listCampus Whether we authorize
6891
 *
6892
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
6893
 */
6894
function api_register_campus($listCampus = true)
6895
{
6896
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6897
6898
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
6899
    Database::query($sql);
6900
6901
    if (!$listCampus) {
6902
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
6903
        Database::query($sql);
6904
    }
6905
}
6906
6907
/**
6908
 * Checks whether current user is a student boss.
6909
 *
6910
 * @global array $_user
6911
 *
6912
 * @return bool
6913
 */
6914
function api_is_student_boss()
6915
{
6916
    $_user = api_get_user_info();
6917
6918
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
6919
}
6920
6921
/**
6922
 * Check whether the user type should be exclude.
6923
 * Such as invited or anonymous users.
6924
 *
6925
 * @param bool $checkDB Optional. Whether check the user status
6926
 * @param int  $userId  Options. The user id
6927
 *
6928
 * @return bool
6929
 */
6930
function api_is_excluded_user_type($checkDB = false, $userId = 0)
6931
{
6932
    if ($checkDB) {
6933
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
6934
6935
        if (0 == $userId) {
6936
            return true;
6937
        }
6938
6939
        $userInfo = api_get_user_info($userId);
6940
6941
        switch ($userInfo['status']) {
6942
            case INVITEE:
6943
            case ANONYMOUS:
6944
                return true;
6945
            default:
6946
                return false;
6947
        }
6948
    }
6949
6950
    $isInvited = api_is_invitee();
6951
    $isAnonymous = api_is_anonymous();
6952
6953
    if ($isInvited || $isAnonymous) {
6954
        return true;
6955
    }
6956
6957
    return false;
6958
}
6959
6960
/**
6961
 * Get the user status to ignore in reports.
6962
 *
6963
 * @param string $format Optional. The result type (array or string)
6964
 *
6965
 * @return array|string
6966
 */
6967
function api_get_users_status_ignored_in_reports($format = 'array')
6968
{
6969
    $excludedTypes = [
6970
        INVITEE,
6971
        ANONYMOUS,
6972
    ];
6973
6974
    if ('string' == $format) {
6975
        return implode(', ', $excludedTypes);
6976
    }
6977
6978
    return $excludedTypes;
6979
}
6980
6981
/**
6982
 * Set the Site Use Cookie Warning for 1 year.
6983
 */
6984
function api_set_site_use_cookie_warning_cookie()
6985
{
6986
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
6987
}
6988
6989
/**
6990
 * Return true if the Site Use Cookie Warning Cookie warning exists.
6991
 *
6992
 * @return bool
6993
 */
6994
function api_site_use_cookie_warning_cookie_exist()
6995
{
6996
    return isset($_COOKIE['ChamiloUsesCookies']);
6997
}
6998
6999
/**
7000
 * Given a number of seconds, format the time to show hours, minutes and seconds.
7001
 *
7002
 * @param int    $time         The time in seconds
7003
 * @param string $originFormat Optional. PHP o JS
7004
 *
7005
 * @return string (00h00'00")
7006
 */
7007
function api_format_time($time, $originFormat = 'php')
7008
{
7009
    $h = get_lang('h');
7010
    $hours = $time / 3600;
7011
    $mins = ($time % 3600) / 60;
7012
    $secs = ($time % 60);
7013
7014
    if ($time < 0) {
7015
        $hours = 0;
7016
        $mins = 0;
7017
        $secs = 0;
7018
    }
7019
7020
    if ('js' === $originFormat) {
7021
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
7022
    } else {
7023
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
7024
    }
7025
7026
    return $formattedTime;
7027
}
7028
7029
/**
7030
 * Sends an email
7031
 * Sender name and email can be specified, if not specified
7032
 * name and email of the platform admin are used.
7033
 *
7034
 * @param string    name of recipient
7035
 * @param string    email of recipient
7036
 * @param string    email subject
7037
 * @param string    email body
7038
 * @param string    sender name
7039
 * @param string    sender e-mail
7040
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
7041
 * @param array     data file (path and filename)
7042
 * @param bool      True for attaching a embedded file inside content html (optional)
7043
 * @param array     Additional parameters
7044
 *
7045
 * @return bool true if mail was sent
7046
 */
7047
function api_mail_html(
7048
    $recipientName,
7049
    $recipientEmail,
7050
    $subject,
7051
    $body,
7052
    $senderName = '',
7053
    $senderEmail = '',
7054
    $extra_headers = [],
7055
    $data_file = [],
7056
    $embeddedImage = false,
7057
    $additionalParameters = []
7058
) {
7059
    if (!api_valid_email($recipientEmail)) {
7060
        return false;
7061
    }
7062
7063
    // Default values
7064
    $notification = new Notification();
7065
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
7066
    $defaultName = $notification->getDefaultPlatformSenderName();
7067
7068
    // If the parameter is set don't use the admin.
7069
    $senderName = !empty($senderName) ? $senderName : $defaultName;
7070
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
7071
7072
    // Reply to first
7073
    $replyToName = '';
7074
    $replyToEmail = '';
7075
    if (isset($extra_headers['reply_to'])) {
7076
        $replyToEmail = $extra_headers['reply_to']['mail'];
7077
        $replyToName = $extra_headers['reply_to']['name'];
7078
    }
7079
7080
    try {
7081
        $message = new TemplatedEmail();
7082
        $message->subject($subject);
7083
7084
        $list = api_get_configuration_value('send_all_emails_to');
7085
        if (!empty($list) && isset($list['emails'])) {
7086
            foreach ($list['emails'] as $email) {
7087
                $message->cc($email);
7088
            }
7089
        }
7090
7091
        // Attachment
7092
        if (!empty($data_file)) {
7093
            foreach ($data_file as $file_attach) {
7094
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
7095
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
7096
                }
7097
            }
7098
        }
7099
7100
        $noReply = api_get_setting('noreply_email_address');
7101
        $automaticEmailText = '';
7102
        if (!empty($noReply)) {
7103
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
7104
        }
7105
7106
        $params = [
7107
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
7108
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
7109
            'link' => $additionalParameters['link'] ?? '',
7110
            'automatic_email_text' => $automaticEmailText,
7111
            'content' => $body,
7112
            'theme' => api_get_visual_theme(),
7113
        ];
7114
7115
        if (!empty($senderEmail)) {
7116
            $message->from(new Address($senderEmail, $senderName));
7117
        }
7118
7119
        if (!empty($recipientEmail)) {
7120
            $message->to(new Address($recipientEmail, $recipientName));
7121
        }
7122
7123
        if (!empty($replyToEmail)) {
7124
            $message->replyTo(new Address($replyToEmail, $replyToName));
7125
        }
7126
7127
        $message
7128
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
7129
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
7130
        ;
7131
        $message->context($params);
7132
        Container::getMailer()->send($message);
7133
7134
        return true;
7135
    } catch (Exception $e) {
7136
        error_log($e->getMessage());
7137
    }
7138
7139
    if (!empty($additionalParameters)) {
7140
        $plugin = new AppPlugin();
7141
        $smsPlugin = $plugin->getSMSPluginLibrary();
7142
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
7143
            $smsPlugin->send($additionalParameters);
7144
        }
7145
    }
7146
7147
    return 1;
7148
}
7149
7150
/**
7151
 * @param int  $tool       Possible values: GroupManager::GROUP_TOOL_*
7152
 * @param bool $showHeader
7153
 */
7154
function api_protect_course_group($tool, $showHeader = true)
7155
{
7156
    $groupId = api_get_group_id();
7157
    if (!empty($groupId)) {
7158
        if (api_is_platform_admin()) {
7159
            return true;
7160
        }
7161
7162
        if (api_is_allowed_to_edit(false, true, true)) {
7163
            return true;
7164
        }
7165
7166
        $userId = api_get_user_id();
7167
        $sessionId = api_get_session_id();
7168
        if (!empty($sessionId)) {
7169
            if (api_is_coach($sessionId, api_get_course_int_id())) {
7170
                return true;
7171
            }
7172
7173
            if (api_is_drh()) {
7174
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
7175
                    return true;
7176
                }
7177
            }
7178
        }
7179
7180
        $group = api_get_group_entity($groupId);
7181
7182
        // Group doesn't exists
7183
        if (null === $group) {
7184
            api_not_allowed($showHeader);
7185
        }
7186
7187
        // Check group access
7188
        $allow = GroupManager::userHasAccess(
7189
            $userId,
7190
            $group,
7191
            $tool
7192
        );
7193
7194
        if (!$allow) {
7195
            api_not_allowed($showHeader);
7196
        }
7197
    }
7198
7199
    return false;
7200
}
7201
7202
/**
7203
 * Check if a date is in a date range.
7204
 *
7205
 * @param datetime $startDate
7206
 * @param datetime $endDate
7207
 * @param datetime $currentDate
7208
 *
7209
 * @return bool true if date is in rage, false otherwise
7210
 */
7211
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
7212
{
7213
    $startDate = strtotime(api_get_local_time($startDate));
7214
    $endDate = strtotime(api_get_local_time($endDate));
7215
    $currentDate = strtotime(api_get_local_time($currentDate));
7216
7217
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
7218
        return true;
7219
    }
7220
7221
    return false;
7222
}
7223
7224
/**
7225
 * Eliminate the duplicates of a multidimensional array by sending the key.
7226
 *
7227
 * @param array $array multidimensional array
7228
 * @param int   $key   key to find to compare
7229
 *
7230
 * @return array
7231
 */
7232
function api_unique_multidim_array($array, $key)
7233
{
7234
    $temp_array = [];
7235
    $i = 0;
7236
    $key_array = [];
7237
7238
    foreach ($array as $val) {
7239
        if (!in_array($val[$key], $key_array)) {
7240
            $key_array[$i] = $val[$key];
7241
            $temp_array[$i] = $val;
7242
        }
7243
        $i++;
7244
    }
7245
7246
    return $temp_array;
7247
}
7248
7249
/**
7250
 * Limit the access to Session Admins when the limit_session_admin_role
7251
 * configuration variable is set to true.
7252
 */
7253
function api_protect_limit_for_session_admin()
7254
{
7255
    $limitAdmin = api_get_setting('limit_session_admin_role');
7256
    if (api_is_session_admin() && 'true' === $limitAdmin) {
7257
        api_not_allowed(true);
7258
    }
7259
}
7260
7261
/**
7262
 * Limits that a session admin has access to list users.
7263
 * When limit_session_admin_list_users configuration variable is set to true.
7264
 */
7265
function api_protect_session_admin_list_users()
7266
{
7267
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
7268
7269
    if (api_is_session_admin() && true === $limitAdmin) {
7270
        api_not_allowed(true);
7271
    }
7272
}
7273
7274
/**
7275
 * @return bool
7276
 */
7277
function api_is_student_view_active()
7278
{
7279
    $studentView = Session::read('studentview');
7280
7281
    return 'studentview' === $studentView;
7282
}
7283
7284
/**
7285
 * Converts string value to float value.
7286
 *
7287
 * 3.141516 => 3.141516
7288
 * 3,141516 => 3.141516
7289
 *
7290
 * @todo WIP
7291
 *
7292
 * @param string $number
7293
 *
7294
 * @return float
7295
 */
7296
function api_float_val($number)
7297
{
7298
    return (float) str_replace(',', '.', trim($number));
7299
}
7300
7301
/**
7302
 * Converts float values
7303
 * Example if $decimals = 2.
7304
 *
7305
 * 3.141516 => 3.14
7306
 * 3,141516 => 3,14
7307
 *
7308
 * @param string $number            number in iso code
7309
 * @param int    $decimals
7310
 * @param string $decimalSeparator
7311
 * @param string $thousandSeparator
7312
 *
7313
 * @return bool|string
7314
 */
7315
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
7316
{
7317
    $number = api_float_val($number);
7318
7319
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
7320
}
7321
7322
/**
7323
 * Set location url with a exit break by default.
7324
 *
7325
 * @param string $url
7326
 * @param bool   $exit
7327
 */
7328
function api_location($url, $exit = true)
7329
{
7330
    header('Location: '.$url);
7331
7332
    if ($exit) {
7333
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
7334
    }
7335
}
7336
7337
/**
7338
 * @param string $from
7339
 * @param string $to
7340
 *
7341
 * @return string
7342
 */
7343
function api_get_relative_path($from, $to)
7344
{
7345
    // some compatibility fixes for Windows paths
7346
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
7347
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
7348
    $from = str_replace('\\', '/', $from);
7349
    $to = str_replace('\\', '/', $to);
7350
7351
    $from = explode('/', $from);
7352
    $to = explode('/', $to);
7353
    $relPath = $to;
7354
7355
    foreach ($from as $depth => $dir) {
7356
        // find first non-matching dir
7357
        if ($dir === $to[$depth]) {
7358
            // ignore this directory
7359
            array_shift($relPath);
7360
        } else {
7361
            // get number of remaining dirs to $from
7362
            $remaining = count($from) - $depth;
7363
            if ($remaining > 1) {
7364
                // add traversals up to first matching dir
7365
                $padLength = (count($relPath) + $remaining - 1) * -1;
7366
                $relPath = array_pad($relPath, $padLength, '..');
7367
                break;
7368
            } else {
7369
                $relPath[0] = './'.$relPath[0];
7370
            }
7371
        }
7372
    }
7373
7374
    return implode('/', $relPath);
7375
}
7376
7377
/**
7378
 * @param string $template
7379
 *
7380
 * @return string
7381
 */
7382
function api_find_template($template)
7383
{
7384
    return Template::findTemplateFilePath($template);
7385
}
7386
7387
/**
7388
 * @return array
7389
 */
7390
function api_get_language_list_for_flag()
7391
{
7392
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
7393
    $sql = "SELECT english_name, isocode FROM $table
7394
            ORDER BY original_name ASC";
7395
    static $languages = [];
7396
    if (empty($languages)) {
7397
        $result = Database::query($sql);
7398
        while ($row = Database::fetch_array($result)) {
7399
            $languages[$row['english_name']] = $row['isocode'];
7400
        }
7401
        $languages['english'] = 'gb';
7402
    }
7403
7404
    return $languages;
7405
}
7406
7407
/**
7408
 * @param string $name
7409
 *
7410
 * @return ZipStream
7411
 */
7412
function api_create_zip($name)
7413
{
7414
    $zipStreamOptions = new Archive();
7415
    $zipStreamOptions->setSendHttpHeaders(true);
7416
    $zipStreamOptions->setContentDisposition('attachment');
7417
    $zipStreamOptions->setContentType('application/x-zip');
7418
7419
    return new ZipStream($name, $zipStreamOptions);
7420
}
7421
7422
/**
7423
 * @return string
7424
 */
7425
function api_get_language_translate_html()
7426
{
7427
    $translate = api_get_configuration_value('translate_html');
7428
7429
    if (!$translate) {
7430
        return '';
7431
    }
7432
7433
    $languageList = api_get_languages();
7434
    $hideAll = '';
7435
    foreach ($languageList['all'] as $language) {
7436
        $hideAll .= '
7437
        $("span:lang('.$language['isocode'].')").filter(
7438
            function(e, val) {
7439
                // Only find the spans if they have set the lang
7440
                if ($(this).attr("lang") == null) {
7441
                    return false;
7442
                }
7443
7444
                // Ignore ckeditor classes
7445
                return !this.className.match(/cke(.*)/);
7446
        }).hide();'."\n";
7447
    }
7448
7449
    $userInfo = api_get_user_info();
7450
    $languageId = api_get_language_id($userInfo['language']);
7451
    $languageInfo = api_get_language_info($languageId);
7452
    $isoCode = 'en';
7453
7454
    if (!empty($languageInfo)) {
7455
        $isoCode = $languageInfo['isocode'];
7456
    }
7457
7458
    return '
7459
            $(function() {
7460
                '.$hideAll.'
7461
                var defaultLanguageFromUser = "'.$isoCode.'";
7462
7463
                $("span:lang('.$isoCode.')").filter(
7464
                    function() {
7465
                        // Ignore ckeditor classes
7466
                        return !this.className.match(/cke(.*)/);
7467
                }).show();
7468
7469
                var defaultLanguage = "";
7470
                var langFromUserFound = false;
7471
7472
                $(this).find("span").filter(
7473
                    function() {
7474
                        // Ignore ckeditor classes
7475
                        return !this.className.match(/cke(.*)/);
7476
                }).each(function() {
7477
                    defaultLanguage = $(this).attr("lang");
7478
                    if (defaultLanguage) {
7479
                        $(this).before().next("br").remove();
7480
                        if (defaultLanguageFromUser == defaultLanguage) {
7481
                            langFromUserFound = true;
7482
                        }
7483
                    }
7484
                });
7485
7486
                // Show default language
7487
                if (langFromUserFound == false && defaultLanguage) {
7488
                    $("span:lang("+defaultLanguage+")").filter(
7489
                    function() {
7490
                            // Ignore ckeditor classes
7491
                            return !this.className.match(/cke(.*)/);
7492
                    }).show();
7493
                }
7494
            });
7495
    ';
7496
}
7497
7498
function api_protect_webservices()
7499
{
7500
    if (api_get_configuration_value('disable_webservices')) {
7501
        echo "Webservices are disabled. \n";
7502
        echo "To enable, add \$_configuration['disable_webservices'] = true; in configuration.php";
7503
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
7504
    }
7505
}
7506