Passed
Pull Request — master (#5614)
by Angel Fernando Quiroz
07:17
created

api_get_visual_theme()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AccessUrl;
6
use Chamilo\CoreBundle\Entity\Course;
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\Exception\NotAllowedException;
13
use Chamilo\CoreBundle\Framework\Container;
14
use Chamilo\CoreBundle\ServiceHelper\MailHelper;
15
use Chamilo\CoreBundle\ServiceHelper\ThemeHelper;
16
use Chamilo\CourseBundle\Entity\CGroup;
17
use Chamilo\CourseBundle\Entity\CLp;
18
use ChamiloSession as Session;
19
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
20
use Symfony\Component\Finder\Finder;
21
use Symfony\Component\Mime\Address;
22
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
23
use Symfony\Component\Security\Core\User\UserInterface;
24
use Symfony\Component\Validator\Constraints as Assert;
25
use ZipStream\Option\Archive;
26
use ZipStream\ZipStream;
27
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
28
use Chamilo\CoreBundle\Component\Utils\ObjectIcon;
29
30
/**
31
 * This is a code library for Chamilo.
32
 * It is included by default in every Chamilo file (through including the global.inc.php)
33
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
34
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
35
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
36
 */
37
38
// PHP version requirement.
39
define('REQUIRED_PHP_VERSION', '8.0');
40
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
41
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
42
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
43
44
// USER STATUS CONSTANTS
45
/** global status of a user: student */
46
define('STUDENT', 5);
47
/** global status of a user: course manager */
48
define('COURSEMANAGER', 1);
49
/** global status of a user: session admin */
50
define('SESSIONADMIN', 3);
51
/** global status of a user: human ressource manager */
52
define('DRH', 4);
53
/** global status of a user: human ressource manager */
54
define('ANONYMOUS', 6);
55
/** global status of a user: low security, necessary for inserting data from
56
 * the teacher through HTMLPurifier */
57
define('COURSEMANAGERLOWSECURITY', 10);
58
// Soft user status
59
define('PLATFORM_ADMIN', 11);
60
define('SESSION_COURSE_COACH', 12);
61
define('SESSION_GENERAL_COACH', 13);
62
define('COURSE_STUDENT', 14); //student subscribed in a course
63
define('SESSION_STUDENT', 15); //student subscribed in a session course
64
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
65
define('STUDENT_BOSS', 17); // student is boss
66
define('INVITEE', 20);
67
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
68
69
// COURSE VISIBILITY CONSTANTS
70
/** only visible for course admin */
71
define('COURSE_VISIBILITY_CLOSED', 0);
72
/** only visible for users registered in the course */
73
define('COURSE_VISIBILITY_REGISTERED', 1);
74
/** Open for all registered users on the platform */
75
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
76
/** Open for the whole world */
77
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
78
/** Invisible to all except admin */
79
define('COURSE_VISIBILITY_HIDDEN', 4);
80
81
define('COURSE_REQUEST_PENDING', 0);
82
define('COURSE_REQUEST_ACCEPTED', 1);
83
define('COURSE_REQUEST_REJECTED', 2);
84
define('DELETE_ACTION_ENABLED', false);
85
86
// EMAIL SENDING RECIPIENT CONSTANTS
87
define('SEND_EMAIL_EVERYONE', 1);
88
define('SEND_EMAIL_STUDENTS', 2);
89
define('SEND_EMAIL_TEACHERS', 3);
90
91
// SESSION VISIBILITY CONSTANTS
92
define('SESSION_VISIBLE_READ_ONLY', 1);
93
define('SESSION_VISIBLE', 2);
94
define('SESSION_INVISIBLE', 3); // not available
95
define('SESSION_AVAILABLE', 4);
96
97
define('SESSION_LINK_TARGET', '_self');
98
99
define('SUBSCRIBE_ALLOWED', 1);
100
define('SUBSCRIBE_NOT_ALLOWED', 0);
101
define('UNSUBSCRIBE_ALLOWED', 1);
102
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
103
104
// SURVEY VISIBILITY CONSTANTS
105
define('SURVEY_VISIBLE_TUTOR', 0);
106
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
107
define('SURVEY_VISIBLE_PUBLIC', 2);
108
109
// CONSTANTS defining all tools, using the english version
110
/* When you add a new tool you must add it into function api_get_tools_lists() too */
111
define('TOOL_DOCUMENT', 'document');
112
define('TOOL_LP_FINAL_ITEM', 'final_item');
113
define('TOOL_READOUT_TEXT', 'readout_text');
114
define('TOOL_THUMBNAIL', 'thumbnail');
115
define('TOOL_HOTPOTATOES', 'hotpotatoes');
116
define('TOOL_CALENDAR_EVENT', 'calendar_event');
117
define('TOOL_LINK', 'link');
118
define('TOOL_LINK_CATEGORY', 'link_category');
119
define('TOOL_COURSE_DESCRIPTION', 'course_description');
120
define('TOOL_SEARCH', 'search');
121
define('TOOL_LEARNPATH', 'learnpath');
122
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
123
define('TOOL_AGENDA', 'agenda');
124
define('TOOL_ANNOUNCEMENT', 'announcement');
125
define('TOOL_FORUM', 'forum');
126
define('TOOL_FORUM_CATEGORY', 'forum_category');
127
define('TOOL_FORUM_THREAD', 'forum_thread');
128
define('TOOL_FORUM_POST', 'forum_post');
129
define('TOOL_FORUM_ATTACH', 'forum_attachment');
130
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
131
define('TOOL_THREAD', 'thread');
132
define('TOOL_POST', 'post');
133
define('TOOL_DROPBOX', 'dropbox');
134
define('TOOL_QUIZ', 'quiz');
135
define('TOOL_TEST_CATEGORY', 'test_category');
136
define('TOOL_USER', 'user');
137
define('TOOL_GROUP', 'group');
138
define('TOOL_BLOGS', 'blog_management');
139
define('TOOL_CHAT', 'chat');
140
define('TOOL_STUDENTPUBLICATION', 'student_publication');
141
define('TOOL_TRACKING', 'tracking');
142
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
143
define('TOOL_COURSE_SETTING', 'course_setting');
144
define('TOOL_BACKUP', 'backup');
145
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
146
define('TOOL_RECYCLE_COURSE', 'recycle_course');
147
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
148
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
149
define('TOOL_UPLOAD', 'file_upload');
150
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
151
define('TOOL_SURVEY', 'survey');
152
//define('TOOL_WIKI', 'wiki');
153
define('TOOL_GLOSSARY', 'glossary');
154
define('TOOL_GRADEBOOK', 'gradebook');
155
define('TOOL_NOTEBOOK', 'notebook');
156
define('TOOL_ATTENDANCE', 'attendance');
157
define('TOOL_COURSE_PROGRESS', 'course_progress');
158
define('TOOL_PORTFOLIO', 'portfolio');
159
define('TOOL_PLAGIARISM', 'compilatio');
160
define('TOOL_XAPI', 'xapi');
161
162
// CONSTANTS defining Chamilo interface sections
163
define('SECTION_CAMPUS', 'mycampus');
164
define('SECTION_COURSES', 'mycourses');
165
define('SECTION_CATALOG', 'catalog');
166
define('SECTION_MYPROFILE', 'myprofile');
167
define('SECTION_MYAGENDA', 'myagenda');
168
define('SECTION_COURSE_ADMIN', 'course_admin');
169
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
170
define('SECTION_MYGRADEBOOK', 'mygradebook');
171
define('SECTION_TRACKING', 'session_my_space');
172
define('SECTION_SOCIAL', 'social-network');
173
define('SECTION_DASHBOARD', 'dashboard');
174
define('SECTION_REPORTS', 'reports');
175
define('SECTION_GLOBAL', 'global');
176
define('SECTION_INCLUDE', 'include');
177
define('SECTION_CUSTOMPAGE', 'custompage');
178
179
// CONSTANT name for local authentication source
180
define('PLATFORM_AUTH_SOURCE', 'platform');
181
define('CAS_AUTH_SOURCE', 'cas');
182
define('LDAP_AUTH_SOURCE', 'extldap');
183
184
// event logs types
185
define('LOG_COURSE_DELETE', 'course_deleted');
186
define('LOG_COURSE_CREATE', 'course_created');
187
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
188
189
// @todo replace 'soc_gr' with social_group
190
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
191
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
192
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
193
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
194
195
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
196
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
197
198
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
199
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
200
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
201
202
define('LOG_MESSAGE_DATA', 'message_data');
203
define('LOG_MESSAGE_DELETE', 'msg_deleted');
204
205
define('LOG_USER_DELETE', 'user_deleted');
206
define('LOG_USER_PREDELETE', 'user_predeleted');
207
define('LOG_USER_CREATE', 'user_created');
208
define('LOG_USER_UPDATE', 'user_updated');
209
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
210
define('LOG_USER_ENABLE', 'user_enable');
211
define('LOG_USER_DISABLE', 'user_disable');
212
define('LOG_USER_ANONYMIZE', 'user_anonymized');
213
define('LOG_USER_FIELD_CREATE', 'user_field_created');
214
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
215
define('LOG_SESSION_CREATE', 'session_created');
216
define('LOG_SESSION_DELETE', 'session_deleted');
217
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
218
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
219
define('LOG_SESSION_ADD_USER', 'session_add_user');
220
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
221
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
222
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
223
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
224
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
225
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
226
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
227
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
228
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
229
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
230
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
231
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
232
define('LOG_PROMOTION_CREATE', 'promotion_created');
233
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
234
define('LOG_CAREER_CREATE', 'career_created');
235
define('LOG_CAREER_DELETE', 'career_deleted');
236
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
237
//define('LOG_WIKI_ACCESS', 'wiki_page_view');
238
// All results from an exercise
239
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
240
// Logs only the one attempt
241
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
242
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
243
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
244
define('LOG_QUESTION_SCORE_UPDATE', 'score_attempt_updated');
245
246
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
247
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
248
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
249
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
250
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
251
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
252
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
253
254
// Event logs data types (max 20 chars)
255
define('LOG_COURSE_CODE', 'course_code');
256
define('LOG_COURSE_ID', 'course_id');
257
define('LOG_USER_ID', 'user_id');
258
define('LOG_USER_OBJECT', 'user_object');
259
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
260
define('LOG_SESSION_ID', 'session_id');
261
262
define('LOG_QUESTION_ID', 'question_id');
263
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
264
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
265
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
266
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
267
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
268
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
269
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
270
define('LOG_CAREER_ID', 'career_id');
271
define('LOG_PROMOTION_ID', 'promotion_id');
272
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
273
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
274
define('LOG_GRADEBOOK_ID', 'gradebook_id');
275
//define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
276
define('LOG_EXERCISE_ID', 'exercise_id');
277
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
278
define('LOG_LP_ID', 'lp_id');
279
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
280
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
281
282
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
283
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
284
define('LOG_WORK_DATA', 'work_data_array');
285
286
define('LOG_MY_FOLDER_PATH', 'path');
287
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
288
289
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
290
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
291
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
292
293
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
294
295
define('LOG_QUESTION_CREATED', 'question_created');
296
define('LOG_QUESTION_UPDATED', 'question_updated');
297
define('LOG_QUESTION_DELETED', 'question_deleted');
298
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
299
300
define('LOG_SURVEY_ID', 'survey_id');
301
define('LOG_SURVEY_CREATED', 'survey_created');
302
define('LOG_SURVEY_DELETED', 'survey_deleted');
303
define('LOG_SURVEY_CLEAN_RESULTS', 'survey_clean_results');
304
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.@\$-]/');
305
306
//used when login_is_email setting is true
307
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
308
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
309
310
// This constant is a result of Windows OS detection, it has a boolean value:
311
// true whether the server runs on Windows OS, false otherwise.
312
define('IS_WINDOWS_OS', api_is_windows_os());
313
314
// Patterns for processing paths. Examples.
315
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
316
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
317
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
318
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
319
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
320
// basic (leaf elements)
321
define('REL_CODE_PATH', 'REL_CODE_PATH');
322
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
323
define('REL_HOME_PATH', 'REL_HOME_PATH');
324
325
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
326
define('WEB_PATH', 'WEB_PATH');
327
define('SYS_PATH', 'SYS_PATH');
328
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
329
330
define('REL_PATH', 'REL_PATH');
331
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
332
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
333
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
334
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
335
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
336
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
337
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
338
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
339
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
340
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
341
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
342
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
343
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
344
define('LIBRARY_PATH', 'LIBRARY_PATH');
345
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
346
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
347
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
348
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
349
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
350
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
351
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
352
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
353
354
// Relations type with Course manager
355
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
356
357
// Relations type with Human resources manager
358
define('COURSE_RELATION_TYPE_RRHH', 1);
359
360
// User image sizes
361
define('USER_IMAGE_SIZE_ORIGINAL', 1);
362
define('USER_IMAGE_SIZE_BIG', 2);
363
define('USER_IMAGE_SIZE_MEDIUM', 3);
364
define('USER_IMAGE_SIZE_SMALL', 4);
365
366
// Gradebook link constants
367
// Please do not change existing values, they are used in the database !
368
define('GRADEBOOK_ITEM_LIMIT', 1000);
369
370
define('LINK_EXERCISE', 1);
371
define('LINK_DROPBOX', 2);
372
define('LINK_STUDENTPUBLICATION', 3);
373
define('LINK_LEARNPATH', 4);
374
define('LINK_FORUM_THREAD', 5);
375
//define('LINK_WORK',6);
376
define('LINK_ATTENDANCE', 7);
377
define('LINK_SURVEY', 8);
378
define('LINK_HOTPOTATOES', 9);
379
define('LINK_PORTFOLIO', 10);
380
381
// Score display types constants
382
define('SCORE_DIV', 1); // X / Y
383
define('SCORE_PERCENT', 2); // XX %
384
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
385
define('SCORE_AVERAGE', 4); // XX %
386
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
387
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
388
define('SCORE_SIMPLE', 7); // X
389
define('SCORE_IGNORE_SPLIT', 8); //  ??
390
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
391
define('SCORE_CUSTOM', 10); // Good!
392
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
393
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
394
define('SCORE_ONLY_SCORE', 13); // X - Good!
395
define('SCORE_NUMERIC', 14);
396
397
define('SCORE_BOTH', 1);
398
define('SCORE_ONLY_DEFAULT', 2);
399
define('SCORE_ONLY_CUSTOM', 3);
400
401
// From display.lib.php
402
403
define('MAX_LENGTH_BREADCRUMB', 100);
404
define('ICON_SIZE_ATOM', 8);
405
define('ICON_SIZE_TINY', 16);
406
define('ICON_SIZE_SMALL', 22);
407
define('ICON_SIZE_MEDIUM', 32);
408
define('ICON_SIZE_LARGE', 48);
409
define('ICON_SIZE_BIG', 64);
410
define('ICON_SIZE_HUGE', 128);
411
define('SHOW_TEXT_NEAR_ICONS', false);
412
413
// Session catalog
414
define('CATALOG_COURSES', 0);
415
define('CATALOG_SESSIONS', 1);
416
define('CATALOG_COURSES_SESSIONS', 2);
417
418
// Hook type events, pre-process and post-process.
419
// All means to be executed for both hook event types
420
define('HOOK_EVENT_TYPE_PRE', 0);
421
define('HOOK_EVENT_TYPE_POST', 1);
422
define('HOOK_EVENT_TYPE_ALL', 10);
423
424
// Group permissions
425
define('GROUP_PERMISSION_OPEN', '1');
426
define('GROUP_PERMISSION_CLOSED', '2');
427
428
// Group user permissions
429
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
430
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
431
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
432
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
433
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
434
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
435
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
436
437
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
438
define('GROUP_IMAGE_SIZE_BIG', 2);
439
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
440
define('GROUP_IMAGE_SIZE_SMALL', 4);
441
define('GROUP_TITLE_LENGTH', 50);
442
443
// Exercise
444
// @todo move into a class
445
define('ALL_ON_ONE_PAGE', 1);
446
define('ONE_PER_PAGE', 2);
447
448
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
449
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
450
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
451
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
452
453
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
454
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
455
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
456
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
457
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
458
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
459
define('RESULT_DISABLE_RANKING', 6);
460
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
461
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
462
define('RESULT_DISABLE_RADAR', 9);
463
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT_NO_FEEDBACK', 10);
464
465
define('EXERCISE_MAX_NAME_SIZE', 80);
466
467
// Question types (edit next array as well when adding values)
468
// @todo move into a class
469
define('UNIQUE_ANSWER', 1);
470
define('MULTIPLE_ANSWER', 2);
471
define('FILL_IN_BLANKS', 3);
472
define('MATCHING', 4);
473
define('FREE_ANSWER', 5);
474
define('HOT_SPOT', 6);
475
define('HOT_SPOT_ORDER', 7);
476
define('HOT_SPOT_DELINEATION', 8);
477
define('MULTIPLE_ANSWER_COMBINATION', 9);
478
define('UNIQUE_ANSWER_NO_OPTION', 10);
479
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
480
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
481
define('ORAL_EXPRESSION', 13);
482
define('GLOBAL_MULTIPLE_ANSWER', 14);
483
define('MEDIA_QUESTION', 15);
484
define('CALCULATED_ANSWER', 16);
485
define('UNIQUE_ANSWER_IMAGE', 17);
486
define('DRAGGABLE', 18);
487
define('MATCHING_DRAGGABLE', 19);
488
define('ANNOTATION', 20);
489
define('READING_COMPREHENSION', 21);
490
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
491
492
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
493
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
494
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
495
496
// Question selection type
497
define('EX_Q_SELECTION_ORDERED', 1);
498
define('EX_Q_SELECTION_RANDOM', 2);
499
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
500
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
501
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
502
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
503
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
504
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
505
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
506
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
507
508
// Used to save the skill_rel_item table
509
define('ITEM_TYPE_EXERCISE', 1);
510
define('ITEM_TYPE_HOTPOTATOES', 2);
511
define('ITEM_TYPE_LINK', 3);
512
define('ITEM_TYPE_LEARNPATH', 4);
513
define('ITEM_TYPE_GRADEBOOK', 5);
514
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
515
//define('ITEM_TYPE_FORUM', 7);
516
define('ITEM_TYPE_ATTENDANCE', 8);
517
define('ITEM_TYPE_SURVEY', 9);
518
define('ITEM_TYPE_FORUM_THREAD', 10);
519
define('ITEM_TYPE_PORTFOLIO', 11);
520
521
// Course description blocks.
522
define('ADD_BLOCK', 8);
523
524
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
525
define(
526
    'QUESTION_TYPES',
527
    UNIQUE_ANSWER.':'.
528
    MULTIPLE_ANSWER.':'.
529
    FILL_IN_BLANKS.':'.
530
    MATCHING.':'.
531
    FREE_ANSWER.':'.
532
    HOT_SPOT.':'.
533
    HOT_SPOT_ORDER.':'.
534
    HOT_SPOT_DELINEATION.':'.
535
    MULTIPLE_ANSWER_COMBINATION.':'.
536
    UNIQUE_ANSWER_NO_OPTION.':'.
537
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
538
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
539
    ORAL_EXPRESSION.':'.
540
    GLOBAL_MULTIPLE_ANSWER.':'.
541
    MEDIA_QUESTION.':'.
542
    CALCULATED_ANSWER.':'.
543
    UNIQUE_ANSWER_IMAGE.':'.
544
    DRAGGABLE.':'.
545
    MATCHING_DRAGGABLE.':'.
546
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
547
    ANNOTATION
548
);
549
550
//Some alias used in the QTI exports
551
define('MCUA', 1);
552
define('TF', 1);
553
define('MCMA', 2);
554
define('FIB', 3);
555
556
// Message
557
define('MESSAGE_STATUS_INVITATION_PENDING', 5);
558
define('MESSAGE_STATUS_INVITATION_ACCEPTED', 6);
559
define('MESSAGE_STATUS_INVITATION_DENIED', 7);
560
define('MESSAGE_STATUS_WALL', 8);
561
562
define('MESSAGE_STATUS_WALL_DELETE', 9);
563
define('MESSAGE_STATUS_WALL_POST', 10);
564
565
define('MESSAGE_STATUS_FORUM', 12);
566
define('MESSAGE_STATUS_PROMOTED', 13);
567
568
// Images
569
define('IMAGE_WALL_SMALL_SIZE', 200);
570
define('IMAGE_WALL_MEDIUM_SIZE', 500);
571
define('IMAGE_WALL_BIG_SIZE', 2000);
572
define('IMAGE_WALL_SMALL', 'small');
573
define('IMAGE_WALL_MEDIUM', 'medium');
574
define('IMAGE_WALL_BIG', 'big');
575
576
// Social PLUGIN PLACES
577
define('SOCIAL_LEFT_PLUGIN', 1);
578
define('SOCIAL_CENTER_PLUGIN', 2);
579
define('SOCIAL_RIGHT_PLUGIN', 3);
580
define('CUT_GROUP_NAME', 50);
581
582
/**
583
 * FormValidator Filter.
584
 */
585
define('NO_HTML', 1);
586
define('STUDENT_HTML', 2);
587
define('TEACHER_HTML', 3);
588
define('STUDENT_HTML_FULLPAGE', 4);
589
define('TEACHER_HTML_FULLPAGE', 5);
590
591
// Timeline
592
define('TIMELINE_STATUS_ACTIVE', '1');
593
define('TIMELINE_STATUS_INACTIVE', '2');
594
595
// Event email template class
596
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
597
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
598
599
// Course home
600
define('SHORTCUTS_HORIZONTAL', 0);
601
define('SHORTCUTS_VERTICAL', 1);
602
603
// Course copy
604
define('FILE_SKIP', 1);
605
define('FILE_RENAME', 2);
606
define('FILE_OVERWRITE', 3);
607
define('UTF8_CONVERT', false); //false by default
608
609
define('DOCUMENT', 'file');
610
define('FOLDER', 'folder');
611
612
define('RESOURCE_ASSET', 'asset');
613
define('RESOURCE_DOCUMENT', 'document');
614
define('RESOURCE_GLOSSARY', 'glossary');
615
define('RESOURCE_EVENT', 'calendar_event');
616
define('RESOURCE_LINK', 'link');
617
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
618
define('RESOURCE_LEARNPATH', 'learnpath');
619
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
620
define('RESOURCE_ANNOUNCEMENT', 'announcement');
621
define('RESOURCE_FORUM', 'forum');
622
define('RESOURCE_FORUMTOPIC', 'thread');
623
define('RESOURCE_FORUMPOST', 'post');
624
define('RESOURCE_QUIZ', 'quiz');
625
define('RESOURCE_TEST_CATEGORY', 'test_category');
626
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
627
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
628
define('RESOURCE_LINKCATEGORY', 'Link_Category');
629
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
630
define('RESOURCE_SCORM', 'Scorm');
631
define('RESOURCE_SURVEY', 'survey');
632
define('RESOURCE_SURVEYQUESTION', 'survey_question');
633
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
634
//define('RESOURCE_WIKI', 'wiki');
635
define('RESOURCE_THEMATIC', 'thematic');
636
define('RESOURCE_ATTENDANCE', 'attendance');
637
define('RESOURCE_WORK', 'work');
638
define('RESOURCE_SESSION_COURSE', 'session_course');
639
define('RESOURCE_GRADEBOOK', 'gradebook');
640
define('ADD_THEMATIC_PLAN', 6);
641
642
// Max online users to show per page (whoisonline)
643
define('MAX_ONLINE_USERS', 12);
644
645
define('TOOL_AUTHORING', 'toolauthoring');
646
define('TOOL_INTERACTION', 'toolinteraction');
647
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
648
define('TOOL_ADMIN', 'tooladmin');
649
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
650
define('TOOL_DRH', 'tool_drh');
651
define('TOOL_STUDENT_VIEW', 'toolstudentview');
652
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
653
654
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
655
// some constants to avoid serialize string keys on serialized data array
656
define('SE_COURSE_ID', 0);
657
define('SE_TOOL_ID', 1);
658
define('SE_DATA', 2);
659
define('SE_USER', 3);
660
661
// in some cases we need top differenciate xapian documents of the same tool
662
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
663
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
664
665
// xapian prefixes
666
define('XAPIAN_PREFIX_COURSEID', 'C');
667
define('XAPIAN_PREFIX_TOOLID', 'O');
668
669
// User active field constants
670
define('USER_ACTIVE', 1);
671
define('USER_INACTIVE', 0);
672
define('USER_INACTIVE_AUTOMATIC', -1);
673
define('USER_SOFT_DELETED', -2);
674
675
/**
676
 * Returns a path to a certain resource within Chamilo.
677
 *
678
 * @param string $path A path which type is to be converted. Also, it may be a defined constant for a path.
679
 *
680
 * @return string the requested path or the converted path
681
 *
682
 * Notes about the current behaviour model:
683
 * 1. Windows back-slashes are converted to slashes in the result.
684
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
685
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
686
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
687
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
688
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
689
 * It has not been identified as needed yet.
690
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
691
 *
692
 * Vchamilo changes : allow using an alternate configuration
693
 * to get vchamilo  instance paths
694
 */
695
function api_get_path($path = '', $configuration = [])
696
{
697
    global $paths;
698
699
    // get proper configuration data if exists
700
    global $_configuration;
701
702
    $emptyConfigurationParam = false;
703
    if (empty($configuration)) {
704
        $configuration = (array) $_configuration;
705
        $emptyConfigurationParam = true;
706
    }
707
708
    $root_sys = Container::getProjectDir();
709
    $root_web = '';
710
    if (isset(Container::$container)) {
711
        $root_web = Container::$container->get('router')->generate(
712
            'index',
713
            [],
714
            UrlGeneratorInterface::ABSOLUTE_URL
715
        );
716
    }
717
718
    if (isset($configuration['multiple_access_urls']) &&
719
        $configuration['multiple_access_urls']
720
    ) {
721
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
722
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
723
            // We look into the DB the function api_get_access_url
724
            $urlInfo = api_get_access_url($configuration['access_url']);
725
            // Avoid default value
726
            $defaultValues = ['http://localhost/', 'https://localhost/'];
727
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
728
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
729
            }
730
        }
731
    }
732
733
    $paths = [
734
        WEB_PATH => $root_web,
735
        SYMFONY_SYS_PATH => $root_sys,
736
        SYS_PATH => $root_sys.'public/',
737
        REL_PATH => '',
738
        CONFIGURATION_PATH => 'app/config/',
739
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
740
741
        REL_COURSE_PATH => '',
742
        REL_CODE_PATH => '/main/',
743
744
        SYS_CODE_PATH => $root_sys.'public/main/',
745
        SYS_CSS_PATH => $root_sys.'public/build/css/',
746
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
747
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
748
        SYS_TEST_PATH => $root_sys.'tests/',
749
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
750
        SYS_PUBLIC_PATH => $root_sys.'public/',
751
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
752
753
        WEB_CODE_PATH => $root_web.'main/',
754
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
755
        WEB_COURSE_PATH => $root_web.'course/',
756
        WEB_IMG_PATH => $root_web.'img/',
757
        WEB_CSS_PATH => $root_web.'build/css/',
758
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
759
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
760
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
761
        WEB_PLUGIN_PATH => $root_web.'plugin/',
762
        WEB_PUBLIC_PATH => $root_web,
763
    ];
764
765
    $root_rel = '';
766
767
    global $virtualChamilo;
768
    if (!empty($virtualChamilo)) {
769
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
770
        //$paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
771
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
772
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
773
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
774
775
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
776
777
        // RewriteEngine On
778
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
779
780
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
781
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
782
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
783
    }
784
785
    $path = trim($path);
786
787
    // Retrieving a common-purpose path.
788
    if (isset($paths[$path])) {
789
        return $paths[$path];
790
    }
791
792
    return false;
793
}
794
795
/**
796
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
797
 *
798
 * @param string $path the input path
799
 *
800
 * @return string returns the modified path
801
 */
802
function api_add_trailing_slash($path)
803
{
804
    return '/' === substr($path, -1) ? $path : $path.'/';
805
}
806
807
/**
808
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
809
 *
810
 * @param string $path the input path
811
 *
812
 * @return string returns the modified path
813
 */
814
function api_remove_trailing_slash($path)
815
{
816
    return '/' === substr($path, -1) ? substr($path, 0, -1) : $path;
817
}
818
819
/**
820
 * Checks the RFC 3986 syntax of a given URL.
821
 *
822
 * @param string $url      the URL to be checked
823
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
824
 *
825
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
826
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
827
 *
828
 * @see http://drupal.org
829
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
830
 * @see http://bugs.php.net/51192
831
 */
832
function api_valid_url($url, $absolute = false)
833
{
834
    if ($absolute) {
835
        if (preg_match("
836
            /^                                                      # Start at the beginning of the text
837
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
838
            (?:                                                     # Userinfo (optional) which is typically
839
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
840
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
841
            )?
842
            (?:
843
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
844
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
845
            )
846
            (?::[0-9]+)?                                            # Server port number (optional)
847
            (?:[\/|\?]
848
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
849
            *)?
850
            $/xi", $url)) {
851
            return $url;
852
        }
853
854
        return false;
855
    } else {
856
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
857
    }
858
}
859
860
/**
861
 * Checks whether a given string looks roughly like an email address.
862
 *
863
 * @param string $address the e-mail address to be checked
864
 *
865
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
866
 */
867
function api_valid_email($address)
868
{
869
    return filter_var($address, FILTER_VALIDATE_EMAIL);
870
}
871
872
/**
873
 * Function used to protect a course script.
874
 * The function blocks access when
875
 * - there is no $_SESSION["_course"] defined; or
876
 * - $is_allowed_in_course is set to false (this depends on the course
877
 * visibility and user status).
878
 *
879
 * This is only the first proposal, test and improve!
880
 *
881
 * @param bool Option to print headers when displaying error message. Default: false
882
 * @param bool whether session admins should be allowed or not
883
 * @param string $checkTool check if tool is available for users (user, group)
884
 *
885
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
886
 *
887
 * @todo replace global variable
888
 *
889
 * @author Roan Embrechts
890
 */
891
function api_protect_course_script($print_headers = false, $allow_session_admins = false, string $checkTool = '', $cid = null): bool
892
{
893
    $course_info = api_get_course_info();
894
    if (empty($course_info) && isset($_REQUEST['cid'])) {
895
        $course_info = api_get_course_info_by_id((int) $_REQUEST['cid']);
896
    }
897
898
    if (isset($cid)) {
899
        $course_info = api_get_course_info_by_id($cid);
900
    }
901
902
    if (empty($course_info)) {
903
        api_not_allowed($print_headers);
904
905
        return false;
906
    }
907
908
    if (api_is_drh()) {
909
        return true;
910
    }
911
912
    // Session admin has access to course
913
    $sessionAccess = ('true' === api_get_setting('session.session_admins_access_all_content'));
914
    if ($sessionAccess) {
915
        $allow_session_admins = true;
916
    }
917
918
    if (api_is_platform_admin($allow_session_admins)) {
919
        return true;
920
    }
921
922
    $isAllowedInCourse = api_is_allowed_in_course();
923
    $is_visible = false;
924
    if (isset($course_info) && isset($course_info['visibility'])) {
925
        switch ($course_info['visibility']) {
926
            default:
927
            case Course::CLOSED:
928
                // Completely closed: the course is only accessible to the teachers. - 0
929
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
930
                    $is_visible = true;
931
                }
932
                break;
933
            case Course::REGISTERED:
934
                // Private - access authorized to course members only - 1
935
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
936
                    $is_visible = true;
937
                }
938
                break;
939
            case Course::OPEN_PLATFORM:
940
                // Open - access allowed for users registered on the platform - 2
941
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
942
                    $is_visible = true;
943
                }
944
                break;
945
            case Course::OPEN_WORLD:
946
                //Open - access allowed for the whole world - 3
947
                $is_visible = true;
948
                break;
949
            case Course::HIDDEN:
950
                //Completely closed: the course is only accessible to the teachers. - 0
951
                if (api_is_platform_admin()) {
952
                    $is_visible = true;
953
                }
954
                break;
955
        }
956
957
        //If password is set and user is not registered to the course then the course is not visible
958
        if (false === $isAllowedInCourse &&
959
            isset($course_info['registration_code']) &&
960
            !empty($course_info['registration_code'])
961
        ) {
962
            $is_visible = false;
963
        }
964
    }
965
966
    if (!empty($checkTool)) {
967
        if (!api_is_allowed_to_edit(true, true, true)) {
968
            $toolInfo = api_get_tool_information_by_name($checkTool);
969
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
970
                api_not_allowed(true);
971
972
                return false;
973
            }
974
        }
975
    }
976
977
    // Check session visibility
978
    $session_id = api_get_session_id();
979
980
    if (!empty($session_id)) {
981
        // $isAllowedInCourse was set in local.inc.php
982
        if (!$isAllowedInCourse) {
983
            $is_visible = false;
984
        }
985
        // Check if course is inside session.
986
        if (!SessionManager::relation_session_course_exist($session_id, $course_info['real_id'])) {
987
            $is_visible = false;
988
        }
989
    }
990
991
    if (!$is_visible) {
992
        api_not_allowed($print_headers);
993
994
        return false;
995
    }
996
997
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
998
        $plugin = Positioning::create();
999
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1000
        if ('true' === $block) {
1001
            $currentPath = $_SERVER['PHP_SELF'];
1002
            // Allowed only this course paths.
1003
            $paths = [
1004
                '/plugin/positioning/start.php',
1005
                '/plugin/positioning/start_student.php',
1006
                '/main/course_home/course_home.php',
1007
                '/main/exercise/overview.php',
1008
            ];
1009
1010
            if (!in_array($currentPath, $paths, true)) {
1011
                // Check if entering an exercise.
1012
                // @todo remove global $current_course_tool
1013
                /*global $current_course_tool;
1014
                if ('quiz' !== $current_course_tool) {
1015
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1016
                    if ($initialData && isset($initialData['exercise_id'])) {
1017
                        $results = Event::getExerciseResultsByUser(
1018
                            api_get_user_id(),
1019
                            $initialData['exercise_id'],
1020
                            $course_info['real_id'],
1021
                            $session_id
1022
                        );
1023
                        if (empty($results)) {
1024
                            api_not_allowed($print_headers);
1025
1026
                            return false;
1027
                        }
1028
                    }
1029
                }*/
1030
            }
1031
        }
1032
    }
1033
1034
    api_block_inactive_user();
1035
1036
    return true;
1037
}
1038
1039
/**
1040
 * Function used to protect an admin script.
1041
 *
1042
 * The function blocks access when the user has no platform admin rights
1043
 * with an error message printed on default output
1044
 *
1045
 * @param bool Whether to allow session admins as well
1046
 * @param bool Whether to allow HR directors as well
1047
 * @param string An optional message (already passed through get_lang)
1048
 *
1049
 * @return bool True if user is allowed, false otherwise.
1050
 *              The function also outputs an error message in case not allowed
1051
 *
1052
 * @author Roan Embrechts (original author)
1053
 */
1054
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1055
{
1056
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1057
        api_not_allowed(true, $message);
1058
1059
        return false;
1060
    }
1061
    api_block_inactive_user();
1062
1063
    return true;
1064
}
1065
1066
/**
1067
 * Blocks inactive users with a currently active session from accessing more pages "live".
1068
 *
1069
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1070
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1071
 */
1072
function api_block_inactive_user()
1073
{
1074
    $data = true;
1075
    if ('true' !== api_get_setting('security.security_block_inactive_users_immediately')) {
1076
        return $data;
1077
    }
1078
1079
    $userId = api_get_user_id();
1080
    $homeUrl = api_get_path(WEB_PATH);
1081
    if (0 == $userId) {
1082
        return $data;
1083
    }
1084
1085
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1086
            WHERE id = $userId";
1087
1088
    $result = Database::query($sql);
1089
    if (Database::num_rows($result) > 0) {
1090
        $result_array = Database::fetch_array($result);
1091
        $data = (bool) $result_array['active'];
1092
    }
1093
    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...
1094
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1095
        $tpl->assign('hide_login_link', 1);
1096
1097
        //api_not_allowed(true, get_lang('Account inactive'));
1098
        // we were not in a course, return to home page
1099
        $msg = Display::return_message(
1100
            get_lang('Account inactive'),
1101
            'error',
1102
            false
1103
        );
1104
1105
        $msg .= '<p class="text-center">
1106
                 <a class="btn btn--plain" href="'.$homeUrl.'">'.get_lang('Back to Home Page.').'</a></p>';
1107
1108
        $tpl->assign('content', $msg);
1109
        $tpl->display_one_col_template();
1110
        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...
1111
    }
1112
1113
    return $data;
1114
}
1115
1116
/**
1117
 * Function used to protect a teacher script.
1118
 * The function blocks access when the user has no teacher rights.
1119
 *
1120
 * @return bool True if the current user can access the script, false otherwise
1121
 *
1122
 * @author Yoselyn Castillo
1123
 */
1124
function api_protect_teacher_script()
1125
{
1126
    if (!api_is_allowed_to_edit()) {
1127
        api_not_allowed(true);
1128
1129
        return false;
1130
    }
1131
1132
    return true;
1133
}
1134
1135
/**
1136
 * Function used to prevent anonymous users from accessing a script.
1137
 *
1138
 * @param bool $printHeaders
1139
 *
1140
 * @return bool
1141
 */
1142
function api_block_anonymous_users($printHeaders = true)
1143
{
1144
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED');
1145
1146
    if (false === $isAuth) {
1147
        api_not_allowed($printHeaders);
1148
1149
        return false;
1150
    }
1151
1152
    api_block_inactive_user();
1153
1154
    return true;
1155
}
1156
1157
/**
1158
 * Returns a rough evaluation of the browser's name and version based on very
1159
 * simple regexp.
1160
 *
1161
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1162
 */
1163
function api_get_navigator()
1164
{
1165
    $navigator = 'Unknown';
1166
    $version = 0;
1167
1168
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1169
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1170
    }
1171
1172
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1173
        $navigator = 'Opera';
1174
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1175
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1176
        $navigator = 'Edge';
1177
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1178
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1179
        $navigator = 'Internet Explorer';
1180
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1181
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1182
        $navigator = 'Chrome';
1183
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1184
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1185
        $navigator = 'Safari';
1186
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1187
            // If this Safari does have the "Version/" string in its user agent
1188
            // then use that as a version indicator rather than what's after
1189
            // "Safari/" which is rather a "build number" or something
1190
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1191
        } else {
1192
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1193
        }
1194
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1195
        $navigator = 'Firefox';
1196
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1197
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1198
        $navigator = 'Netscape';
1199
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1200
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1201
        } else {
1202
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1203
        }
1204
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1205
        $navigator = 'Konqueror';
1206
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1207
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1208
        $navigator = 'AppleWebKit';
1209
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1210
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1211
        $navigator = 'Mozilla';
1212
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1213
    }
1214
1215
    // Now cut extra stuff around (mostly *after*) the version number
1216
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1217
1218
    if (false === strpos($version, '.')) {
1219
        $version = number_format(doubleval($version), 1);
1220
    }
1221
1222
    return ['name' => $navigator, 'version' => $version];
1223
}
1224
1225
/**
1226
 * This function returns the id of the user which is stored in the $_user array.
1227
 *
1228
 * example: The function can be used to check if a user is logged in
1229
 *          if (api_get_user_id())
1230
 *
1231
 * @return int the id of the current user, 0 if is empty
1232
 */
1233
function api_get_user_id()
1234
{
1235
    $userInfo = Session::read('_user');
1236
    if ($userInfo && isset($userInfo['user_id'])) {
1237
        return (int) $userInfo['user_id'];
1238
    }
1239
1240
    return 0;
1241
}
1242
1243
/**
1244
 * Formats user information into a standard array
1245
 * This function should be only used inside api_get_user_info().
1246
 *
1247
 * @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...
1248
 * @param bool $add_password
1249
 * @param bool $loadAvatars  turn off to improve performance
1250
 *
1251
 * @return array Standard user array
1252
 */
1253
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1254
{
1255
    $result = [];
1256
1257
    if (!isset($user['id'])) {
1258
        return [];
1259
    }
1260
1261
    $result['firstname'] = null;
1262
    $result['lastname'] = null;
1263
1264
    if (isset($user['firstname']) && isset($user['lastname'])) {
1265
        // with only lowercase
1266
        $result['firstname'] = $user['firstname'];
1267
        $result['lastname'] = $user['lastname'];
1268
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1269
        // with uppercase letters
1270
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1271
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1272
    }
1273
1274
    if (isset($user['email'])) {
1275
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1276
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1277
    } else {
1278
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1279
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1280
    }
1281
1282
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1283
    $result['complete_name_with_username'] = $result['complete_name'];
1284
1285
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1286
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1287
    }
1288
1289
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1290
    if (!empty($user['email'])) {
1291
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1292
        if ($showEmail) {
1293
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1294
        }
1295
    } else {
1296
        $result['complete_name_with_email'] = $result['complete_name'];
1297
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1298
    }
1299
1300
    // Kept for historical reasons
1301
    $result['firstName'] = $result['firstname'];
1302
    $result['lastName'] = $result['lastname'];
1303
1304
    $attributes = [
1305
        'phone',
1306
        'address',
1307
        'picture_uri',
1308
        'official_code',
1309
        'status',
1310
        'active',
1311
        'auth_source',
1312
        'username',
1313
        'theme',
1314
        'language',
1315
        'locale',
1316
        'creator_id',
1317
        'registration_date',
1318
        'hr_dept_id',
1319
        'expiration_date',
1320
        'last_login',
1321
        'user_is_online',
1322
        'profile_completed',
1323
    ];
1324
1325
    if ('true' === api_get_setting('extended_profile')) {
1326
        $attributes[] = 'competences';
1327
        $attributes[] = 'diplomas';
1328
        $attributes[] = 'teach';
1329
        $attributes[] = 'openarea';
1330
    }
1331
1332
    foreach ($attributes as $attribute) {
1333
        $result[$attribute] = $user[$attribute] ?? null;
1334
    }
1335
1336
    $user_id = (int) $user['id'];
1337
    // Maintain the user_id index for backwards compatibility
1338
    $result['user_id'] = $result['id'] = $user_id;
1339
1340
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1341
    $result['has_certificates'] = 0;
1342
    if (!empty($hasCertificates)) {
1343
        $result['has_certificates'] = 1;
1344
    }
1345
1346
    $result['icon_status'] = '';
1347
    $result['icon_status_medium'] = '';
1348
    $result['is_admin'] = UserManager::is_admin($user_id);
1349
1350
    // Getting user avatar.
1351
    if ($loadAvatars) {
1352
        $result['avatar'] = '';
1353
        $result['avatar_no_query'] = '';
1354
        $result['avatar_small'] = '';
1355
        $result['avatar_medium'] = '';
1356
1357
        if (empty($user['avatar'])) {
1358
            $originalFile = UserManager::getUserPicture(
1359
                $user_id,
1360
                USER_IMAGE_SIZE_ORIGINAL,
1361
                null,
1362
                $result
1363
            );
1364
            $result['avatar'] = $originalFile;
1365
            $avatarString = explode('?', $result['avatar']);
1366
            $result['avatar_no_query'] = reset($avatarString);
1367
        } else {
1368
            $result['avatar'] = $user['avatar'];
1369
            $avatarString = explode('?', $user['avatar']);
1370
            $result['avatar_no_query'] = reset($avatarString);
1371
        }
1372
1373
        if (!isset($user['avatar_small'])) {
1374
            $smallFile = UserManager::getUserPicture(
1375
                $user_id,
1376
                USER_IMAGE_SIZE_SMALL,
1377
                null,
1378
                $result
1379
            );
1380
            $result['avatar_small'] = $smallFile;
1381
        } else {
1382
            $result['avatar_small'] = $user['avatar_small'];
1383
        }
1384
1385
        if (!isset($user['avatar_medium'])) {
1386
            $mediumFile = UserManager::getUserPicture(
1387
                $user_id,
1388
                USER_IMAGE_SIZE_MEDIUM,
1389
                null,
1390
                $result
1391
            );
1392
            $result['avatar_medium'] = $mediumFile;
1393
        } else {
1394
            $result['avatar_medium'] = $user['avatar_medium'];
1395
        }
1396
1397
        $urlImg = api_get_path(WEB_IMG_PATH);
1398
        $iconStatus = '';
1399
        $iconStatusMedium = '';
1400
        $label = '';
1401
1402
        switch ($result['status']) {
1403
            case STUDENT:
1404
                if ($result['has_certificates']) {
1405
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1406
                    $label = get_lang('Graduated');
1407
                } else {
1408
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1409
                    $label = get_lang('Student');
1410
                }
1411
                break;
1412
            case COURSEMANAGER:
1413
                if ($result['is_admin']) {
1414
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1415
                    $label = get_lang('Admin');
1416
                } else {
1417
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1418
                    $label = get_lang('Teacher');
1419
                }
1420
                break;
1421
            case STUDENT_BOSS:
1422
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1423
                $label = get_lang('StudentBoss');
1424
                break;
1425
        }
1426
1427
        if (!empty($iconStatus)) {
1428
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1429
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1430
        }
1431
1432
        $result['icon_status'] = $iconStatus;
1433
        $result['icon_status_label'] = $label;
1434
        $result['icon_status_medium'] = $iconStatusMedium;
1435
    }
1436
1437
    if (isset($user['user_is_online'])) {
1438
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1439
    }
1440
    if (isset($user['user_is_online_in_chat'])) {
1441
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1442
    }
1443
1444
    if ($add_password) {
1445
        $result['password'] = $user['password'];
1446
    }
1447
1448
    if (isset($result['profile_completed'])) {
1449
        $result['profile_completed'] = $user['profile_completed'];
1450
    }
1451
1452
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1453
1454
    // Send message link
1455
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1456
    $result['complete_name_with_message_link'] = Display::url(
1457
        $result['complete_name_with_username'],
1458
        $sendMessage,
1459
        ['class' => 'ajax']
1460
    );
1461
1462
    if (isset($user['extra'])) {
1463
        $result['extra'] = $user['extra'];
1464
    }
1465
1466
    return $result;
1467
}
1468
1469
/**
1470
 * Finds all the information about a user.
1471
 * If no parameter is passed you find all the information about the current user.
1472
 *
1473
 * @param int  $user_id
1474
 * @param bool $checkIfUserOnline
1475
 * @param bool $showPassword
1476
 * @param bool $loadExtraData
1477
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1478
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1479
 * @param bool $updateCache              update apc cache if exists
1480
 *
1481
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1482
 *
1483
 * @author Patrick Cool <[email protected]>
1484
 * @author Julio Montoya
1485
 *
1486
 * @version 21 September 2004
1487
 */
1488
function api_get_user_info(
1489
    $user_id = 0,
1490
    $checkIfUserOnline = false,
1491
    $showPassword = false,
1492
    $loadExtraData = false,
1493
    $loadOnlyVisibleExtraData = false,
1494
    $loadAvatars = true,
1495
    $updateCache = false
1496
) {
1497
    // Make sure user_id is safe
1498
    $user_id = (int) $user_id;
1499
    $user = false;
1500
    if (empty($user_id)) {
1501
        $userFromSession = Session::read('_user');
1502
        if (isset($userFromSession) && !empty($userFromSession)) {
1503
            return $userFromSession;
1504
            /*
1505
            return _api_format_user(
1506
                $userFromSession,
1507
                $showPassword,
1508
                $loadAvatars
1509
            );*/
1510
        }
1511
1512
        return false;
1513
    }
1514
1515
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1516
            WHERE id = $user_id";
1517
    $result = Database::query($sql);
1518
    if (Database::num_rows($result) > 0) {
1519
        $result_array = Database::fetch_array($result);
1520
        $result_array['user_is_online_in_chat'] = 0;
1521
        if ($checkIfUserOnline) {
1522
            $use_status_in_platform = user_is_online($user_id);
1523
            $result_array['user_is_online'] = $use_status_in_platform;
1524
            $user_online_in_chat = 0;
1525
            if ($use_status_in_platform) {
1526
                $user_status = UserManager::get_extra_user_data_by_field(
1527
                    $user_id,
1528
                    'user_chat_status',
1529
                    false,
1530
                    true
1531
                );
1532
                if (1 == (int) $user_status['user_chat_status']) {
1533
                    $user_online_in_chat = 1;
1534
                }
1535
            }
1536
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1537
        }
1538
1539
        if ($loadExtraData) {
1540
            $fieldValue = new ExtraFieldValue('user');
1541
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1542
                $user_id,
1543
                $loadOnlyVisibleExtraData
1544
            );
1545
        }
1546
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1547
    }
1548
1549
    return $user;
1550
}
1551
1552
function api_get_user_info_from_entity(
1553
    User $user,
1554
    $checkIfUserOnline = false,
1555
    $showPassword = false,
1556
    $loadExtraData = false,
1557
    $loadOnlyVisibleExtraData = false,
1558
    $loadAvatars = true,
1559
    $loadCertificate = false
1560
) {
1561
    if (!$user instanceof UserInterface) {
1562
        return false;
1563
    }
1564
1565
    // Make sure user_id is safe
1566
    $user_id = (int) $user->getId();
1567
1568
    if (empty($user_id)) {
1569
        $userFromSession = Session::read('_user');
1570
1571
        if (isset($userFromSession) && !empty($userFromSession)) {
1572
            return $userFromSession;
1573
        }
1574
1575
        return false;
1576
    }
1577
1578
    $result = [];
1579
    $result['user_is_online_in_chat'] = 0;
1580
    if ($checkIfUserOnline) {
1581
        $use_status_in_platform = user_is_online($user_id);
1582
        $result['user_is_online'] = $use_status_in_platform;
1583
        $user_online_in_chat = 0;
1584
        if ($use_status_in_platform) {
1585
            $user_status = UserManager::get_extra_user_data_by_field(
1586
                $user_id,
1587
                'user_chat_status',
1588
                false,
1589
                true
1590
            );
1591
            if (1 == (int) $user_status['user_chat_status']) {
1592
                $user_online_in_chat = 1;
1593
            }
1594
        }
1595
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1596
    }
1597
1598
    if ($loadExtraData) {
1599
        $fieldValue = new ExtraFieldValue('user');
1600
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1601
            $user_id,
1602
            $loadOnlyVisibleExtraData
1603
        );
1604
    }
1605
1606
    $result['username'] = $user->getUsername();
1607
    $result['status'] = $user->getStatus();
1608
    $result['firstname'] = $user->getFirstname();
1609
    $result['lastname'] = $user->getLastname();
1610
    $result['email'] = $result['mail'] = $user->getEmail();
1611
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1612
    $result['complete_name_with_username'] = $result['complete_name'];
1613
1614
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1615
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1616
    }
1617
1618
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1619
    if (!empty($result['email'])) {
1620
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1621
        if ($showEmail) {
1622
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1623
        }
1624
    } else {
1625
        $result['complete_name_with_email'] = $result['complete_name'];
1626
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1627
    }
1628
1629
    // Kept for historical reasons
1630
    $result['firstName'] = $result['firstname'];
1631
    $result['lastName'] = $result['lastname'];
1632
1633
    $attributes = [
1634
        'picture_uri',
1635
        'last_login',
1636
        'user_is_online',
1637
    ];
1638
1639
    $result['phone'] = $user->getPhone();
1640
    $result['address'] = $user->getAddress();
1641
    $result['official_code'] = $user->getOfficialCode();
1642
    $result['active'] = $user->isActive();
1643
    $result['auth_source'] = $user->getAuthSource();
1644
    $result['language'] = $user->getLocale();
1645
    $result['creator_id'] = $user->getCreatorId();
1646
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1647
    $result['hr_dept_id'] = $user->getHrDeptId();
1648
    $result['expiration_date'] = '';
1649
    if ($user->getExpirationDate()) {
1650
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1651
    }
1652
1653
    $result['last_login'] = null;
1654
    if ($user->getLastLogin()) {
1655
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1656
    }
1657
1658
    $result['competences'] = $user->getCompetences();
1659
    $result['diplomas'] = $user->getDiplomas();
1660
    $result['teach'] = $user->getTeach();
1661
    $result['openarea'] = $user->getOpenarea();
1662
    $user_id = (int) $user->getId();
1663
1664
    // Maintain the user_id index for backwards compatibility
1665
    $result['user_id'] = $result['id'] = $user_id;
1666
1667
    if ($loadCertificate) {
1668
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1669
        $result['has_certificates'] = 0;
1670
        if (!empty($hasCertificates)) {
1671
            $result['has_certificates'] = 1;
1672
        }
1673
    }
1674
1675
    $result['icon_status'] = '';
1676
    $result['icon_status_medium'] = '';
1677
    $result['is_admin'] = UserManager::is_admin($user_id);
1678
1679
    // Getting user avatar.
1680
    if ($loadAvatars) {
1681
        $result['avatar'] = '';
1682
        $result['avatar_no_query'] = '';
1683
        $result['avatar_small'] = '';
1684
        $result['avatar_medium'] = '';
1685
        $urlImg = '/';
1686
        $iconStatus = '';
1687
        $iconStatusMedium = '';
1688
1689
        switch ($user->getStatus()) {
1690
            case STUDENT:
1691
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1692
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1693
                } else {
1694
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1695
                }
1696
                break;
1697
            case COURSEMANAGER:
1698
                if ($result['is_admin']) {
1699
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1700
                } else {
1701
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1702
                }
1703
                break;
1704
            case STUDENT_BOSS:
1705
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1706
                break;
1707
        }
1708
1709
        if (!empty($iconStatus)) {
1710
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1711
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1712
        }
1713
1714
        $result['icon_status'] = $iconStatus;
1715
        $result['icon_status_medium'] = $iconStatusMedium;
1716
    }
1717
1718
    if (isset($result['user_is_online'])) {
1719
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1720
    }
1721
    if (isset($result['user_is_online_in_chat'])) {
1722
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1723
    }
1724
1725
    $result['password'] = '';
1726
    if ($showPassword) {
1727
        $result['password'] = $user->getPassword();
1728
    }
1729
1730
    if (isset($result['profile_completed'])) {
1731
        $result['profile_completed'] = $result['profile_completed'];
1732
    }
1733
1734
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1735
1736
    // Send message link
1737
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1738
    $result['complete_name_with_message_link'] = Display::url(
1739
        $result['complete_name_with_username'],
1740
        $sendMessage,
1741
        ['class' => 'ajax']
1742
    );
1743
1744
    if (isset($result['extra'])) {
1745
        $result['extra'] = $result['extra'];
1746
    }
1747
1748
    return $result;
1749
}
1750
1751
function api_get_lp_entity(int $id): ?CLp
1752
{
1753
    return Database::getManager()->getRepository(CLp::class)->find($id);
1754
}
1755
1756
function api_get_user_entity(int $userId = 0): ?User
1757
{
1758
    $userId = $userId ?: api_get_user_id();
1759
    $repo = Container::getUserRepository();
1760
1761
    return $repo->find($userId);
1762
}
1763
1764
function api_get_current_user(): ?User
1765
{
1766
    $isLoggedIn = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_REMEMBERED');
1767
    if (false === $isLoggedIn) {
1768
        return null;
1769
    }
1770
1771
    $token = Container::getTokenStorage()->getToken();
1772
1773
    if (null !== $token) {
1774
        return $token->getUser();
1775
    }
1776
1777
    return null;
1778
}
1779
1780
/**
1781
 * Finds all the information about a user from username instead of user id.
1782
 *
1783
 * @param string $username
1784
 *
1785
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1786
 *
1787
 * @author Yannick Warnier <[email protected]>
1788
 */
1789
function api_get_user_info_from_username($username)
1790
{
1791
    if (empty($username)) {
1792
        return false;
1793
    }
1794
    $username = trim($username);
1795
1796
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1797
            WHERE username='".Database::escape_string($username)."'";
1798
    $result = Database::query($sql);
1799
    if (Database::num_rows($result) > 0) {
1800
        $resultArray = Database::fetch_array($result);
1801
1802
        return _api_format_user($resultArray);
1803
    }
1804
1805
    return false;
1806
}
1807
1808
/**
1809
 * Get first user with an email.
1810
 *
1811
 * @param string $email
1812
 *
1813
 * @return array|bool
1814
 */
1815
function api_get_user_info_from_email($email = '')
1816
{
1817
    if (empty($email)) {
1818
        return false;
1819
    }
1820
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1821
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1822
    $result = Database::query($sql);
1823
    if (Database::num_rows($result) > 0) {
1824
        $resultArray = Database::fetch_array($result);
1825
1826
        return _api_format_user($resultArray);
1827
    }
1828
1829
    return false;
1830
}
1831
1832
/**
1833
 * @return string
1834
 */
1835
function api_get_course_id()
1836
{
1837
    return Session::read('_cid', null);
1838
}
1839
1840
/**
1841
 * Returns the current course id (integer).
1842
 *
1843
 * @param ?string $code Optional course code
1844
 *
1845
 * @return int
1846
 */
1847
function api_get_course_int_id(?string $code = null): int
1848
{
1849
    if (!empty($code)) {
1850
        $code = Database::escape_string($code);
1851
        $row = Database::select(
1852
            'id',
1853
            Database::get_main_table(TABLE_MAIN_COURSE),
1854
            ['where' => ['code = ?' => [$code]]],
1855
            'first'
1856
        );
1857
1858
        if (is_array($row) && isset($row['id'])) {
1859
            return $row['id'];
1860
        } else {
1861
            return 0;
1862
        }
1863
    }
1864
1865
    $cid = Session::read('_real_cid', 0);
1866
    if (empty($cid) && isset($_REQUEST['cid'])) {
1867
        $cid = (int) $_REQUEST['cid'];
1868
    }
1869
1870
    return $cid;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $cid could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
1871
}
1872
1873
/**
1874
 * Gets a course setting from the current course_setting table. Try always using integer values.
1875
 *
1876
 * @param string       $settingName The name of the setting we want from the table
1877
 * @param Course|array $courseInfo
1878
 * @param bool         $force       force checking the value in the database
1879
 *
1880
 * @return mixed The value of that setting in that table. Return -1 if not found.
1881
 */
1882
function api_get_course_setting($settingName, $courseInfo = null, $force = false)
1883
{
1884
    if (empty($courseInfo)) {
1885
        $courseInfo = api_get_course_info();
1886
    }
1887
1888
    if (empty($courseInfo) || empty($settingName)) {
1889
        return -1;
1890
    }
1891
1892
    if ($courseInfo instanceof Course) {
1893
        $courseId = $courseInfo->getId();
1894
    } else {
1895
        $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1896
    }
1897
1898
    if (empty($courseId)) {
1899
        return -1;
1900
    }
1901
1902
    static $courseSettingInfo = [];
1903
1904
    if ($force) {
1905
        $courseSettingInfo = [];
1906
    }
1907
1908
    if (!isset($courseSettingInfo[$courseId])) {
1909
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
1910
        $settingName = Database::escape_string($settingName);
1911
1912
        $sql = "SELECT variable, value FROM $table
1913
                WHERE c_id = $courseId ";
1914
        $res = Database::query($sql);
1915
        if (Database::num_rows($res) > 0) {
1916
            $result = Database::store_result($res, 'ASSOC');
1917
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
1918
1919
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
1920
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
1921
                if (!is_null($value)) {
1922
                    $result = explode(',', $value);
1923
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
1924
                }
1925
            }
1926
        }
1927
    }
1928
1929
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
1930
        return $courseSettingInfo[$courseId][$settingName];
1931
    }
1932
1933
    return -1;
1934
}
1935
1936
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
1937
{
1938
    $value = api_get_course_setting($settingName, $courseInfo, true);
1939
1940
    if (-1 === $value) {
1941
        // Check global settings
1942
        $value = api_get_plugin_setting($plugin, $settingName);
1943
        if ('true' === $value) {
1944
            return 1;
1945
        }
1946
        if ('false' === $value) {
1947
            return 0;
1948
        }
1949
        if (null === $value) {
1950
            return -1;
1951
        }
1952
    }
1953
1954
    return $value;
1955
}
1956
1957
/**
1958
 * Gets an anonymous user ID.
1959
 *
1960
 * For some tools that need tracking, like the learnpath tool, it is necessary
1961
 * to have a usable user-id to enable some kind of tracking, even if not
1962
 * perfect. An anonymous ID is taken from the users table by looking for a
1963
 * status of "6" (anonymous).
1964
 *
1965
 * @return int User ID of the anonymous user, or O if no anonymous user found
1966
 */
1967
function api_get_anonymous_id()
1968
{
1969
    // Find if another anon is connected now
1970
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1971
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1972
    $ip = Database::escape_string(api_get_real_ip());
1973
    $max = (int) api_get_setting('admin.max_anonymous_users');
1974
    if ($max >= 2) {
1975
        $sql = "SELECT * FROM $table as TEL
1976
                JOIN $tableU as U
1977
                ON U.id = TEL.login_user_id
1978
                WHERE TEL.user_ip = '$ip'
1979
                    AND U.status = ".ANONYMOUS."
1980
                    AND U.id != 2 ";
1981
1982
        $result = Database::query($sql);
1983
        if (empty(Database::num_rows($result))) {
1984
            $login = uniqid('anon_');
1985
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1986
            if (count($anonList) >= $max) {
1987
                foreach ($anonList as $userToDelete) {
1988
                    UserManager::delete_user($userToDelete['user_id']);
1989
                    break;
1990
                }
1991
            }
1992
1993
            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...
1994
                $login,
1995
                'anon',
1996
                ANONYMOUS,
1997
                ' anonymous@localhost',
1998
                $login,
1999
                $login
2000
            );
2001
        } else {
2002
            $row = Database::fetch_assoc($result);
2003
2004
            return $row['id'];
2005
        }
2006
    }
2007
2008
    $table = Database::get_main_table(TABLE_MAIN_USER);
2009
    $sql = "SELECT id
2010
            FROM $table
2011
            WHERE status = ".ANONYMOUS." ";
2012
    $res = Database::query($sql);
2013
    if (Database::num_rows($res) > 0) {
2014
        $row = Database::fetch_assoc($res);
2015
2016
        return $row['id'];
2017
    }
2018
2019
    // No anonymous user was found.
2020
    return 0;
2021
}
2022
2023
/**
2024
 * @param int $courseId
2025
 * @param int $sessionId
2026
 * @param int $groupId
2027
 *
2028
 * @return string
2029
 */
2030
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2031
{
2032
    $courseId = !empty($courseId) ? (int) $courseId : 0;
2033
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2034
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2035
2036
    $url = 'cid='.$courseId;
2037
    $url .= '&sid='.$sessionId;
2038
    $url .= '&gid='.$groupId;
2039
2040
    return $url;
2041
}
2042
2043
/**
2044
 * Returns the current course url part including session, group, and gradebook params.
2045
 *
2046
 * @param bool   $addSessionId
2047
 * @param bool   $addGroupId
2048
 * @param string $origin
2049
 *
2050
 * @return string Course & session references to add to a URL
2051
 */
2052
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2053
{
2054
    $courseId = api_get_course_int_id();
2055
    if (0 === $courseId && isset($_REQUEST['cid'])) {
2056
        $courseId = (int) $_REQUEST['cid'];
2057
    }
2058
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2059
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2060
2061
    if ($addSessionId) {
2062
        if (!empty($url)) {
2063
            $sessionId = api_get_session_id();
2064
            if (0 === $sessionId && isset($_REQUEST['sid'])) {
2065
                $sessionId = (int) $_REQUEST['sid'];
2066
            }
2067
            $url .= 0 === $sessionId ? '&sid=0' : '&sid='.$sessionId;
2068
        }
2069
    }
2070
2071
    if ($addGroupId) {
2072
        if (!empty($url)) {
2073
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2074
        }
2075
    }
2076
2077
    if (!empty($url)) {
2078
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2079
        if (false !== $origin) {
2080
            $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

2080
            $url .= '&origin=' . /** @scrutinizer ignore-type */ $origin;
Loading history...
2081
        }
2082
    }
2083
2084
    return $url;
2085
}
2086
2087
/**
2088
 * Get if we visited a gradebook page.
2089
 *
2090
 * @return bool
2091
 */
2092
function api_is_in_gradebook()
2093
{
2094
    return Session::read('in_gradebook', false);
2095
}
2096
2097
/**
2098
 * Set that we are in a page inside a gradebook.
2099
 */
2100
function api_set_in_gradebook()
2101
{
2102
    Session::write('in_gradebook', true);
2103
}
2104
2105
/**
2106
 * Remove gradebook session.
2107
 */
2108
function api_remove_in_gradebook()
2109
{
2110
    Session::erase('in_gradebook');
2111
}
2112
2113
/**
2114
 * Returns the current course info array see api_format_course_array()
2115
 * If the course_code is given, the returned array gives info about that
2116
 * particular course, if none given it gets the course info from the session.
2117
 *
2118
 * @param string $courseCode
2119
 *
2120
 * @return array
2121
 */
2122
function api_get_course_info($courseCode = null)
2123
{
2124
    if (!empty($courseCode)) {
2125
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2126
2127
        return api_format_course_array($course);
2128
    }
2129
2130
    $course = Session::read('_course');
2131
    if ('-1' == $course) {
2132
        $course = [];
2133
    }
2134
2135
    if (empty($course) && isset($_REQUEST['cid'])) {
2136
        $course = api_get_course_info_by_id((int) $_REQUEST['cid']);
2137
    }
2138
2139
    return $course;
2140
}
2141
2142
/**
2143
 * @param int $courseId
2144
 */
2145
function api_get_course_entity($courseId = 0): ?Course
2146
{
2147
    if (empty($courseId)) {
2148
        $courseId = api_get_course_int_id();
2149
    }
2150
2151
    if (empty($courseId)) {
2152
        return null;
2153
    }
2154
2155
    return Container::getCourseRepository()->find($courseId);
2156
}
2157
2158
/**
2159
 * @param int $id
2160
 */
2161
function api_get_session_entity($id = 0): ?SessionEntity
2162
{
2163
    if (empty($id)) {
2164
        $id = api_get_session_id();
2165
    }
2166
2167
    if (empty($id)) {
2168
        return null;
2169
    }
2170
2171
    return Container::getSessionRepository()->find($id);
2172
}
2173
2174
/**
2175
 * @param int $id
2176
 */
2177
function api_get_group_entity($id = 0): ?CGroup
2178
{
2179
    if (empty($id)) {
2180
        $id = api_get_group_id();
2181
    }
2182
2183
    return Container::getGroupRepository()->find($id);
2184
}
2185
2186
/**
2187
 * @param int $id
2188
 */
2189
function api_get_url_entity($id = 0): ?AccessUrl
2190
{
2191
    if (empty($id)) {
2192
        $id = api_get_current_access_url_id();
2193
    }
2194
2195
    return Container::getAccessUrlRepository()->find($id);
2196
}
2197
2198
/**
2199
 * Returns the current course info array.
2200
2201
 * Now if the course_code is given, the returned array gives info about that
2202
 * particular course, not specially the current one.
2203
 *
2204
 * @param int $id Numeric ID of the course
2205
 *
2206
 * @return array The course info as an array formatted by api_format_course_array, including category.title
2207
 */
2208
function api_get_course_info_by_id(?int $id = 0)
2209
{
2210
    if (empty($id)) {
2211
        $course = Session::read('_course', []);
2212
2213
        return $course;
2214
    }
2215
2216
    $course = Container::getCourseRepository()->find($id);
2217
    if (empty($course)) {
2218
        return [];
2219
    }
2220
2221
    return api_format_course_array($course);
2222
}
2223
2224
/**
2225
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2226
 * to switch from 'code' to 'id' in the array.
2227
 *
2228
 * @return array
2229
 *
2230
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2231
 */
2232
function api_format_course_array(Course $course = null)
2233
{
2234
    if (empty($course)) {
2235
        return [];
2236
    }
2237
2238
    $courseData = [];
2239
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2240
2241
    // Added
2242
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2243
    $courseData['name'] = $courseData['title'] = $course->getTitle(); // 'name' only used for backwards compatibility - should be removed in the long run
2244
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2245
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2246
    $courseData['titular'] = $course->getTutorName();
2247
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2248
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2249
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2250
2251
    $courseData['visibility'] = $course->getVisibility();
2252
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2253
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2254
    $courseData['activate_legal'] = $course->getActivateLegal();
2255
    $courseData['legal'] = $course->getLegal();
2256
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2257
    $courseData['video_url'] = $course->getVideoUrl();
2258
    $courseData['sticky'] = (int) $course->isSticky();
2259
2260
    $coursePath = '/course/';
2261
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2262
2263
    // Course password
2264
    $courseData['registration_code'] = $course->getRegistrationCode();
2265
    $courseData['disk_quota'] = $course->getDiskQuota();
2266
    $courseData['course_public_url'] = $webCourseHome;
2267
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2268
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2269
2270
    $image = Display::getMdiIcon(
2271
        ObjectIcon::COURSE,
2272
        'ch-tool-icon',
2273
        null,
2274
        ICON_SIZE_BIG
2275
    );
2276
2277
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2278
    if (!empty($illustration)) {
2279
        $image = $illustration;
2280
    }
2281
2282
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2283
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2284
2285
    return $courseData;
2286
}
2287
2288
/**
2289
 * Returns a difficult to guess password.
2290
 */
2291
function api_generate_password(int $length = 8, $useRequirements = true): string
2292
{
2293
    if ($length < 2) {
2294
        $length = 2;
2295
    }
2296
2297
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2298
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2299
    $charactersSpecials = '!@#$%^&*()_+-=[]{}|;:,.<>?';
2300
    $minNumbers = 2;
2301
    $length = $length - $minNumbers;
2302
    $minLowerCase = round($length / 2);
2303
    $minUpperCase = $length - $minLowerCase;
2304
    $minSpecials = 1; // Default minimum special characters
2305
2306
    $password = '';
2307
    $passwordRequirements = $useRequirements ? Security::getPasswordRequirements() : [];
2308
2309
    $factory = new RandomLib\Factory();
2310
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2311
2312
    if (!empty($passwordRequirements)) {
2313
        $length = $passwordRequirements['min']['length'];
2314
        $minNumbers = $passwordRequirements['min']['numeric'];
2315
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2316
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2317
        $minSpecials = $passwordRequirements['min']['specials'];
2318
2319
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase - $minSpecials;
2320
        // Add the rest to fill the length requirement
2321
        if ($rest > 0) {
2322
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2323
        }
2324
    }
2325
2326
    // Min digits default 2
2327
    for ($i = 0; $i < $minNumbers; $i++) {
2328
        $password .= $generator->generateInt(2, 9);
2329
    }
2330
2331
    // Min lowercase
2332
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2333
2334
    // Min uppercase
2335
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2336
2337
    // Min special characters
2338
    $password .= $generator->generateString($minSpecials, $charactersSpecials);
2339
2340
    // Shuffle the password to ensure randomness
2341
    $password = str_shuffle($password);
2342
2343
    return $password;
2344
}
2345
2346
/**
2347
 * Checks a password to see wether it is OK to use.
2348
 *
2349
 * @param string $password
2350
 *
2351
 * @return bool if the password is acceptable, false otherwise
2352
 *              Notes about what a password "OK to use" is:
2353
 *              1. The password should be at least 5 characters long.
2354
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2355
 *              3. The password should contain at least 3 letters.
2356
 *              4. It should contain at least 2 digits.
2357
 *              Settings will change if the configuration value is set: password_requirements
2358
 */
2359
function api_check_password($password)
2360
{
2361
    $passwordRequirements = Security::getPasswordRequirements();
2362
2363
    $minLength = $passwordRequirements['min']['length'];
2364
    $minNumbers = $passwordRequirements['min']['numeric'];
2365
    // Optional
2366
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2367
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2368
2369
    $minLetters = $minLowerCase + $minUpperCase;
2370
    $passwordLength = api_strlen($password);
2371
2372
    $conditions = [
2373
        'min_length' => $passwordLength >= $minLength,
2374
    ];
2375
2376
    $digits = 0;
2377
    $lowerCase = 0;
2378
    $upperCase = 0;
2379
2380
    for ($i = 0; $i < $passwordLength; $i++) {
2381
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2382
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2383
            $upperCase++;
2384
        }
2385
2386
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2387
            $lowerCase++;
2388
        }
2389
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2390
            $digits++;
2391
        }
2392
    }
2393
2394
    // Min number of digits
2395
    $conditions['min_numeric'] = $digits >= $minNumbers;
2396
2397
    if (!empty($minUpperCase)) {
2398
        // Uppercase
2399
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2400
    }
2401
2402
    if (!empty($minLowerCase)) {
2403
        // Lowercase
2404
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2405
    }
2406
2407
    // Min letters
2408
    $letters = $upperCase + $lowerCase;
2409
    $conditions['min_letters'] = $letters >= $minLetters;
2410
2411
    $isPasswordOk = true;
2412
    foreach ($conditions as $condition) {
2413
        if (false === $condition) {
2414
            $isPasswordOk = false;
2415
            break;
2416
        }
2417
    }
2418
2419
    if (false === $isPasswordOk) {
2420
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2421
        $output .= Security::getPasswordRequirementsToString($conditions);
2422
2423
        Display::addFlash(Display::return_message($output, 'warning', false));
2424
    }
2425
2426
    return $isPasswordOk;
2427
}
2428
2429
/**
2430
 * Gets the current Chamilo (not PHP/cookie) session ID.
2431
 *
2432
 * @return int O if no active session, the session ID otherwise
2433
 */
2434
function api_get_session_id()
2435
{
2436
    return (int) Session::read('sid', 0);
2437
}
2438
2439
/**
2440
 * Gets the current Chamilo (not social network) group ID.
2441
 *
2442
 * @return int O if no active session, the session ID otherwise
2443
 */
2444
function api_get_group_id()
2445
{
2446
    return Session::read('gid', 0);
2447
}
2448
2449
/**
2450
 * Gets the current or given session name.
2451
 *
2452
 * @param   int     Session ID (optional)
2453
 *
2454
 * @return string The session name, or null if not found
2455
 */
2456
function api_get_session_name($session_id = 0)
2457
{
2458
    if (empty($session_id)) {
2459
        $session_id = api_get_session_id();
2460
        if (empty($session_id)) {
2461
            return null;
2462
        }
2463
    }
2464
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2465
    $s = "SELECT title FROM $t WHERE id = ".(int) $session_id;
2466
    $r = Database::query($s);
2467
    $c = Database::num_rows($r);
2468
    if ($c > 0) {
2469
        //technically, there can be only one, but anyway we take the first
2470
        $rec = Database::fetch_array($r);
2471
2472
        return $rec['title'];
2473
    }
2474
2475
    return null;
2476
}
2477
2478
/**
2479
 * Gets the session info by id.
2480
 *
2481
 * @param int $id Session ID
2482
 *
2483
 * @return array information of the session
2484
 */
2485
function api_get_session_info($id)
2486
{
2487
    return SessionManager::fetch($id);
2488
}
2489
2490
/**
2491
 * Gets the session visibility by session id.
2492
 *
2493
 * @param int  $session_id
2494
 * @param int  $courseId
2495
 * @param bool $ignore_visibility_for_admins
2496
 *
2497
 * @return int
2498
 *             0 = session still available,
2499
 *             SESSION_VISIBLE_READ_ONLY = 1,
2500
 *             SESSION_VISIBLE = 2,
2501
 *             SESSION_INVISIBLE = 3
2502
 */
2503
function api_get_session_visibility(
2504
    $session_id,
2505
    $courseId = null,
2506
    $ignore_visibility_for_admins = true,
2507
    $userId = 0
2508
) {
2509
    if (api_is_platform_admin()) {
2510
        if ($ignore_visibility_for_admins) {
2511
            return SESSION_AVAILABLE;
2512
        }
2513
    }
2514
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2515
2516
    $now = time();
2517
    if (empty($session_id)) {
2518
        return 0; // Means that the session is still available.
2519
    }
2520
2521
    $session_id = (int) $session_id;
2522
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2523
2524
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2525
2526
    if (Database::num_rows($result) <= 0) {
2527
        return SESSION_INVISIBLE;
2528
    }
2529
2530
    $row = Database::fetch_assoc($result);
2531
    $visibility = $row['visibility'];
2532
2533
    // I don't care the session visibility.
2534
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2535
        // Session duration per student.
2536
        if (isset($row['duration']) && !empty($row['duration'])) {
2537
            $duration = $row['duration'] * 24 * 60 * 60;
2538
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2539
2540
            // If there is a session duration but there is no previous
2541
            // access by the user, then the session is still available
2542
            if (0 == count($courseAccess)) {
2543
                return SESSION_AVAILABLE;
2544
            }
2545
2546
            $currentTime = time();
2547
            $firstAccess = isset($courseAccess['login_course_date'])
2548
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2549
                : 0;
2550
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2551
            $userDuration = isset($userDurationData['duration'])
2552
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2553
                : 0;
2554
2555
            $totalDuration = $firstAccess + $duration + $userDuration;
2556
2557
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2558
        }
2559
2560
        return SESSION_AVAILABLE;
2561
    }
2562
2563
    // If start date was set.
2564
    if (!empty($row['access_start_date'])) {
2565
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2566
    }
2567
2568
    // If the end date was set.
2569
    if (!empty($row['access_end_date'])) {
2570
        // Only if date_start said that it was ok
2571
        if (SESSION_AVAILABLE === $visibility) {
2572
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2573
                ? SESSION_AVAILABLE // Date still available
2574
                : $row['visibility']; // Session ends
2575
        }
2576
    }
2577
2578
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2579
    $isCoach = api_is_coach($session_id, $courseId);
2580
2581
    if ($isCoach) {
2582
        // Test start date.
2583
        if (!empty($row['coach_access_start_date'])) {
2584
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2585
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2586
        }
2587
2588
        // Test end date.
2589
        if (!empty($row['coach_access_end_date'])) {
2590
            if (SESSION_AVAILABLE === $visibility) {
2591
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2592
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2593
            }
2594
        }
2595
    }
2596
2597
    return $visibility;
2598
}
2599
2600
/**
2601
 * This function returns a (star) session icon if the session is not null and
2602
 * the user is not a student.
2603
 *
2604
 * @param int $sessionId
2605
 * @param int $statusId  User status id - if 5 (student), will return empty
2606
 *
2607
 * @return string Session icon
2608
 */
2609
function api_get_session_image($sessionId, User $user)
2610
{
2611
    $sessionId = (int) $sessionId;
2612
    $image = '';
2613
    if (!$user->hasRole('ROLE_STUDENT')) {
2614
        // Check whether is not a student
2615
        if ($sessionId > 0) {
2616
            $image = '&nbsp;&nbsp;'.Display::getMdiIcon(
2617
                ObjectIcon::STAR,
2618
                'ch-tool-icon',
2619
                'align:absmiddle;',
2620
                ICON_SIZE_SMALL,
2621
                get_lang('Session-specific resource')
2622
            );
2623
        }
2624
    }
2625
2626
    return $image;
2627
}
2628
2629
/**
2630
 * This function add an additional condition according to the session of the course.
2631
 *
2632
 * @param int    $session_id        session id
2633
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2634
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2635
 *                                  false for strict session condition
2636
 * @param string $session_field
2637
 *
2638
 * @return string condition of the session
2639
 */
2640
function api_get_session_condition(
2641
    $session_id,
2642
    $and = true,
2643
    $with_base_content = false,
2644
    $session_field = 'session_id'
2645
) {
2646
    $session_id = (int) $session_id;
2647
2648
    if (empty($session_field)) {
2649
        $session_field = 'session_id';
2650
    }
2651
    // Condition to show resources by session
2652
    $condition_add = $and ? ' AND ' : ' WHERE ';
2653
2654
    if ($with_base_content) {
2655
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2656
    } else {
2657
        if (empty($session_id)) {
2658
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2659
        } else {
2660
            $condition_session = $condition_add." $session_field = $session_id ";
2661
        }
2662
    }
2663
2664
    return $condition_session;
2665
}
2666
2667
/**
2668
 * Returns the value of a setting from the web-adjustable admin config settings.
2669
 *
2670
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2671
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2672
 * instead of
2673
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2674
 *
2675
 * @param string $variable The variable name
2676
 *
2677
 * @return string|array
2678
 */
2679
function api_get_setting($variable, $isArray = false, $key = null)
2680
{
2681
    $settingsManager = Container::getSettingsManager();
2682
    if (empty($settingsManager)) {
2683
        return '';
2684
    }
2685
    $variable = trim($variable);
2686
2687
    switch ($variable) {
2688
        case 'server_type':
2689
            $test = ['dev', 'test'];
2690
            $environment = Container::getEnvironment();
2691
            if (in_array($environment, $test)) {
2692
                return 'test';
2693
            }
2694
2695
            return 'prod';
2696
        // deprecated settings
2697
        // no break
2698
        case 'openid_authentication':
2699
        case 'service_ppt2lp':
2700
        case 'formLogin_hide_unhide_label':
2701
            return false;
2702
            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...
2703
        case 'tool_visible_by_default_at_creation':
2704
            $values = $settingsManager->getSetting($variable);
2705
            $newResult = [];
2706
            foreach ($values as $parameter) {
2707
                $newResult[$parameter] = 'true';
2708
            }
2709
2710
            return $newResult;
2711
            break;
2712
        default:
2713
            $settingValue = $settingsManager->getSetting($variable, true);
2714
            if (is_string($settingValue) && $isArray && !empty($settingValue)) {
2715
                // Check if the value is a valid JSON string
2716
                $decodedValue = json_decode($settingValue, true);
2717
2718
                // If it's a valid JSON string and the result is an array, return it
2719
                if (is_array($decodedValue)) {
2720
                    return $decodedValue;
2721
                }
2722
2723
                // If it's not an array, continue with the normal flow
2724
                // Optional: If you need to evaluate the value using eval
2725
                $strArrayValue = rtrim($settingValue, ';');
2726
                $value = eval("return $strArrayValue;");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
2727
                if (is_array($value)) {
2728
                    return $value;
2729
                }
2730
            }
2731
2732
            // If the value is not a JSON array or wasn't returned previously, continue with the normal flow
2733
            if (!empty($key) && isset($settingValue[$variable][$key])) {
2734
                return $settingValue[$variable][$key];
2735
            }
2736
2737
            return $settingValue;
2738
            break;
2739
    }
2740
}
2741
2742
/**
2743
 * @param string $variable
2744
 * @param string $option
2745
 *
2746
 * @return bool
2747
 */
2748
function api_get_setting_in_list($variable, $option)
2749
{
2750
    $value = api_get_setting($variable);
2751
2752
    return in_array($option, $value);
2753
}
2754
2755
/**
2756
 * @param string $plugin
2757
 * @param string $variable
2758
 *
2759
 * @return string
2760
 */
2761
function api_get_plugin_setting($plugin, $variable)
2762
{
2763
    $variableName = $plugin.'_'.$variable;
2764
    //$result = api_get_setting($variableName);
2765
    $params = [
2766
        'category = ? AND subkey = ? AND variable = ?' => [
2767
            'Plugins',
2768
            $plugin,
2769
            $variableName,
2770
        ],
2771
    ];
2772
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2773
    $result = Database::select(
2774
        'selected_value',
2775
        $table,
2776
        ['where' => $params],
2777
        'one'
2778
    );
2779
    if ($result) {
2780
        $value = $result['selected_value'];
2781
        $serializedValue = @unserialize($result['selected_value'], []);
2782
        if (false !== $serializedValue) {
2783
            $value = $serializedValue;
2784
        }
2785
2786
        return $value;
2787
    }
2788
2789
    return null;
2790
    /// Old code
2791
2792
    $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...
2793
    $result = api_get_setting($variableName);
2794
2795
    if (isset($result[$plugin])) {
2796
        $value = $result[$plugin];
2797
2798
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2799
2800
        if (false !== $unserialized) {
2801
            $value = $unserialized;
2802
        }
2803
2804
        return $value;
2805
    }
2806
2807
    return null;
2808
}
2809
2810
/**
2811
 * Returns the value of a setting from the web-adjustable admin config settings.
2812
 */
2813
function api_get_settings_params($params)
2814
{
2815
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2816
2817
    return Database::select('*', $table, ['where' => $params]);
2818
}
2819
2820
/**
2821
 * @param array $params example: [id = ? => '1']
2822
 *
2823
 * @return array
2824
 */
2825
function api_get_settings_params_simple($params)
2826
{
2827
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2828
2829
    return Database::select('*', $table, ['where' => $params], 'one');
0 ignored issues
show
Bug Best Practice introduced by
The expression return Database::select(...re' => $params), 'one') also could return the type integer which is incompatible with the documented return type array.
Loading history...
2830
}
2831
2832
/**
2833
 * Returns the value of a setting from the web-adjustable admin config settings.
2834
 */
2835
function api_delete_settings_params($params)
2836
{
2837
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2838
2839
    return Database::delete($table, $params);
2840
}
2841
2842
/**
2843
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2844
 *
2845
 * @return string Escaped version of $_SERVER['PHP_SELF']
2846
 */
2847
function api_get_self()
2848
{
2849
    return htmlentities($_SERVER['PHP_SELF']);
2850
}
2851
2852
/**
2853
 * Checks whether current user is a platform administrator.
2854
 *
2855
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2856
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2857
 *
2858
 * @return bool true if the user has platform admin rights,
2859
 *              false otherwise
2860
 *
2861
 * @see usermanager::is_admin(user_id) for a user-id specific function
2862
 */
2863
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2864
{
2865
    $currentUser = api_get_current_user();
2866
2867
    if (null === $currentUser) {
2868
        return false;
2869
    }
2870
2871
    $isAdmin = $currentUser->hasRole('ROLE_ADMIN') || $currentUser->hasRole('ROLE_SUPER_ADMIN');
2872
2873
    if ($isAdmin) {
2874
        return true;
2875
    }
2876
2877
    if ($allowSessionAdmins && $currentUser->hasRole('ROLE_SESSION_MANAGER')) {
2878
        return true;
2879
    }
2880
2881
    if ($allowDrh && $currentUser->hasRole('ROLE_RRHH')) {
2882
        return true;
2883
    }
2884
2885
    return false;
2886
}
2887
2888
/**
2889
 * Checks whether the user given as user id is in the admin table.
2890
 *
2891
 * @param int $user_id If none provided, will use current user
2892
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2893
 *
2894
 * @return bool True if the user is admin, false otherwise
2895
 */
2896
function api_is_platform_admin_by_id($user_id = null, $url = null)
2897
{
2898
    $user_id = (int) $user_id;
2899
    if (empty($user_id)) {
2900
        $user_id = api_get_user_id();
2901
    }
2902
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2903
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2904
    $res = Database::query($sql);
2905
    $is_admin = 1 === Database::num_rows($res);
2906
    if (!$is_admin || !isset($url)) {
2907
        return $is_admin;
2908
    }
2909
    // We get here only if $url is set
2910
    $url = (int) $url;
2911
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2912
    $sql = "SELECT * FROM $url_user_table
2913
            WHERE access_url_id = $url AND user_id = $user_id";
2914
    $res = Database::query($sql);
2915
2916
    return 1 === Database::num_rows($res);
2917
}
2918
2919
/**
2920
 * Checks whether current user is allowed to create courses.
2921
 *
2922
 * @return bool true if the user has course creation rights,
2923
 *              false otherwise
2924
 */
2925
function api_is_allowed_to_create_course()
2926
{
2927
    if (api_is_platform_admin()) {
2928
        return true;
2929
    }
2930
2931
    // Teachers can only create courses
2932
    if (api_is_teacher()) {
2933
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
2934
            return true;
2935
        } else {
2936
            return false;
2937
        }
2938
    }
2939
2940
    return Session::read('is_allowedCreateCourse');
2941
}
2942
2943
/**
2944
 * Checks whether the current user is a course administrator.
2945
 *
2946
 * @return bool True if current user is a course administrator
2947
 */
2948
function api_is_course_admin()
2949
{
2950
    if (api_is_platform_admin()) {
2951
        return true;
2952
    }
2953
2954
    $user = api_get_current_user();
2955
    if ($user) {
2956
        if (
2957
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
2958
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
2959
        ) {
2960
            return true;
2961
        }
2962
    }
2963
2964
    return false;
2965
}
2966
2967
/**
2968
 * Checks whether the current user is a course coach
2969
 * Based on the presence of user in session_rel_user.relation_type (as session general coach, value 3).
2970
 *
2971
 * @return bool True if current user is a course coach
2972
 */
2973
function api_is_session_general_coach()
2974
{
2975
    return Session::read('is_session_general_coach');
2976
}
2977
2978
/**
2979
 * Checks whether the current user is a course tutor
2980
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
2981
 *
2982
 * @return bool True if current user is a course tutor
2983
 */
2984
function api_is_course_tutor()
2985
{
2986
    return Session::read('is_courseTutor');
2987
}
2988
2989
/**
2990
 * @param int $user_id
2991
 * @param int $courseId
2992
 * @param int $session_id
2993
 *
2994
 * @return bool
2995
 */
2996
function api_is_course_session_coach($user_id, $courseId, $session_id)
2997
{
2998
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2999
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3000
3001
    $user_id = (int) $user_id;
3002
    $session_id = (int) $session_id;
3003
    $courseId = (int) $courseId;
3004
3005
    $sql = "SELECT DISTINCT session.id
3006
            FROM $session_table
3007
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3008
            ON session.id = session_rc_ru.session_id
3009
            WHERE
3010
                session_rc_ru.user_id = '".$user_id."'  AND
3011
                session_rc_ru.c_id = '$courseId' AND
3012
                session_rc_ru.status = ".SessionEntity::COURSE_COACH." AND
3013
                session_rc_ru.session_id = '$session_id'";
3014
    $result = Database::query($sql);
3015
3016
    return Database::num_rows($result) > 0;
3017
}
3018
3019
/**
3020
 * Checks whether the current user is a course or session coach.
3021
 *
3022
 * @param int $session_id
3023
 * @param int $courseId
3024
 * @param bool  Check whether we are in student view and, if we are, return false
3025
 * @param int $userId
3026
 *
3027
 * @return bool True if current user is a course or session coach
3028
 */
3029
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
3030
{
3031
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
3032
3033
    if (!empty($session_id)) {
3034
        $session_id = (int) $session_id;
3035
    } else {
3036
        $session_id = api_get_session_id();
3037
    }
3038
3039
    // The student preview was on
3040
    if ($check_student_view && api_is_student_view_active()) {
3041
        return false;
3042
    }
3043
3044
    if (!empty($courseId)) {
3045
        $courseId = (int) $courseId;
3046
    } else {
3047
        $courseId = api_get_course_int_id();
3048
    }
3049
3050
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3051
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3052
    $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3053
    $sessionIsCoach = [];
3054
3055
    if (!empty($courseId)) {
3056
        $sql = "SELECT DISTINCT s.id, title, access_start_date, access_end_date
3057
                FROM $session_table s
3058
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3059
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3060
                WHERE
3061
                    session_rc_ru.c_id = '$courseId' AND
3062
                    session_rc_ru.status =".SessionEntity::COURSE_COACH." AND
3063
                    session_rc_ru.session_id = '$session_id'";
3064
        $result = Database::query($sql);
3065
        $sessionIsCoach = Database::store_result($result);
3066
    }
3067
3068
    if (!empty($session_id)) {
3069
        $sql = "SELECT DISTINCT s.id
3070
                FROM $session_table AS s
3071
                INNER JOIN $tblSessionRelUser sru
3072
                ON s.id = sru.session_id
3073
                WHERE
3074
                    sru.user_id = $userId AND
3075
                    s.id = $session_id AND
3076
                    sru.relation_type = ".SessionEntity::GENERAL_COACH."
3077
                ORDER BY s.access_start_date, s.access_end_date, s.title";
3078
        $result = Database::query($sql);
3079
        if (!empty($sessionIsCoach)) {
3080
            $sessionIsCoach = array_merge(
3081
                $sessionIsCoach,
3082
                Database::store_result($result)
3083
            );
3084
        } else {
3085
            $sessionIsCoach = Database::store_result($result);
3086
        }
3087
    }
3088
3089
    return count($sessionIsCoach) > 0;
3090
}
3091
3092
function api_user_has_role(string $role, ?User $user = null): bool
3093
{
3094
    if (null === $user) {
3095
        $user = api_get_current_user();
3096
    }
3097
3098
    if (null === $user) {
3099
        return false;
3100
    }
3101
3102
    return $user->hasRole($role);
3103
}
3104
3105
function api_is_allowed_in_course(): bool
3106
{
3107
    if (api_is_platform_admin()) {
3108
        return true;
3109
    }
3110
3111
    $user = api_get_current_user();
3112
    if ($user instanceof User) {
3113
        if ($user->hasRole('ROLE_CURRENT_COURSE_SESSION_STUDENT') ||
3114
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
3115
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
3116
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3117
        ) {
3118
            return true;
3119
        }
3120
    }
3121
3122
    return false;
3123
}
3124
3125
/**
3126
 * Checks whether current user is a student boss.
3127
 */
3128
function api_is_student_boss(?User $user = null): bool
3129
{
3130
    return api_user_has_role('ROLE_STUDENT_BOSS', $user);
3131
}
3132
3133
/**
3134
 * Checks whether the current user is a session administrator.
3135
 *
3136
 * @return bool True if current user is a course administrator
3137
 */
3138
function api_is_session_admin(?User $user = null)
3139
{
3140
    return api_user_has_role('ROLE_SESSION_MANAGER', $user);
3141
}
3142
3143
/**
3144
 * Checks whether the current user is a human resources manager.
3145
 *
3146
 * @return bool True if current user is a human resources manager
3147
 */
3148
function api_is_drh()
3149
{
3150
    return api_user_has_role('ROLE_RRHH');
3151
}
3152
3153
/**
3154
 * Checks whether the current user is a student.
3155
 *
3156
 * @return bool True if current user is a human resources manager
3157
 */
3158
function api_is_student()
3159
{
3160
    return api_user_has_role('ROLE_STUDENT');
3161
}
3162
3163
/**
3164
 * Checks whether the current user has the status 'teacher'.
3165
 *
3166
 * @return bool True if current user is a human resources manager
3167
 */
3168
function api_is_teacher()
3169
{
3170
    return api_user_has_role('ROLE_TEACHER');
3171
}
3172
3173
/**
3174
 * Checks whether the current user is a invited user.
3175
 *
3176
 * @return bool
3177
 */
3178
function api_is_invitee()
3179
{
3180
    return api_user_has_role('ROLE_INVITEE');
3181
}
3182
3183
/**
3184
 * This function checks whether a session is assigned into a category.
3185
 *
3186
 * @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...
3187
 * @param string    - category name
3188
 *
3189
 * @return bool - true if is found, otherwise false
3190
 */
3191
function api_is_session_in_category($session_id, $category_name)
3192
{
3193
    $session_id = (int) $session_id;
3194
    $category_name = Database::escape_string($category_name);
3195
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3196
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3197
3198
    $sql = "SELECT 1
3199
            FROM $tbl_session
3200
            WHERE $session_id IN (
3201
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3202
                WHERE
3203
                  s.session_category_id = sc.id AND
3204
                  sc.name LIKE '%$category_name'
3205
            )";
3206
    $rs = Database::query($sql);
3207
3208
    if (Database::num_rows($rs) > 0) {
3209
        return true;
3210
    }
3211
3212
    return false;
3213
}
3214
3215
/**
3216
 * Displays options for switching between student view and course manager view.
3217
 *
3218
 * Changes in version 1.2 (Patrick Cool)
3219
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3220
 * is changed explicitly
3221
 *
3222
 * Changes in version 1.1 (Patrick Cool)
3223
 * student view now works correctly in subfolders of the document tool
3224
 * student view works correctly in the new links tool
3225
 *
3226
 * Example code for using this in your tools:
3227
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3228
 * //   display_tool_view_option($isStudentView);
3229
 * //}
3230
 * //and in later sections, use api_is_allowed_to_edit()
3231
 *
3232
 * @author Roan Embrechts
3233
 * @author Patrick Cool
3234
 * @author Julio Montoya, changes added in Chamilo
3235
 *
3236
 * @version 1.2
3237
 *
3238
 * @todo rewrite code so it is easier to understand
3239
 */
3240
function api_display_tool_view_option()
3241
{
3242
    if ('true' != api_get_setting('student_view_enabled')) {
3243
        return '';
3244
    }
3245
3246
    $sourceurl = '';
3247
    $is_framed = false;
3248
    // Exceptions apply for all multi-frames pages
3249
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3250
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3251
        return '';
3252
    }
3253
3254
    // Uncomment to remove student view link from document view page
3255
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3256
        if (empty($_GET['lp_id'])) {
3257
            return '';
3258
        }
3259
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3260
        $sourceurl = str_replace(
3261
            'lp/lp_header.php',
3262
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3263
            $sourceurl
3264
        );
3265
        //showinframes doesn't handle student view anyway...
3266
        //return '';
3267
        $is_framed = true;
3268
    }
3269
3270
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3271
    if (!$is_framed) {
3272
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3273
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3274
        } else {
3275
            $sourceurl = $_SERVER['REQUEST_URI'];
3276
        }
3277
    }
3278
3279
    $output_string = '';
3280
    if (!empty($_SESSION['studentview'])) {
3281
        if ('studentview' == $_SESSION['studentview']) {
3282
            // We have to remove the isStudentView=true from the $sourceurl
3283
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3284
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3285
            $output_string .= '<a class="btn btn--primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3286
                Display::getMdiIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3287
        } elseif ('teacherview' == $_SESSION['studentview']) {
3288
            // Switching to teacherview
3289
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3290
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3291
            $output_string .= '<a class="btn btn--plain btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3292
                Display::getMdiIcon('eye').' '.get_lang('Switch to student view').'</a>';
3293
        }
3294
    } else {
3295
        $output_string .= '<a class="btn btn--plain btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3296
            Display::getMdiIcon('eye').' '.get_lang('Switch to student view').'</a>';
3297
    }
3298
    $output_string = Security::remove_XSS($output_string);
3299
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3300
3301
    return $html;
3302
}
3303
3304
/**
3305
 * Function that removes the need to directly use is_courseAdmin global in
3306
 * tool scripts. It returns true or false depending on the user's rights in
3307
 * this particular course.
3308
 * Optionally checking for tutor and coach roles here allows us to use the
3309
 * student_view feature altogether with these roles as well.
3310
 *
3311
 * @param bool  Whether to check if the user has the tutor role
3312
 * @param bool  Whether to check if the user has the coach role
3313
 * @param bool  Whether to check if the user has the session coach role
3314
 * @param bool  check the student view or not
3315
 *
3316
 * @author Roan Embrechts
3317
 * @author Patrick Cool
3318
 * @author Julio Montoya
3319
 *
3320
 * @version 1.1, February 2004
3321
 *
3322
 * @return bool true: the user has the rights to edit, false: he does not
3323
 */
3324
function api_is_allowed_to_edit(
3325
    $tutor = false,
3326
    $coach = false,
3327
    $session_coach = false,
3328
    $check_student_view = true
3329
) {
3330
    $allowSessionAdminEdit = 'true' === api_get_setting('session.session_admins_edit_courses_content');
3331
    // Admins can edit anything.
3332
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3333
        //The student preview was on
3334
        if ($check_student_view && api_is_student_view_active()) {
3335
            return false;
3336
        }
3337
3338
        return true;
3339
    }
3340
3341
    $sessionId = api_get_session_id();
3342
3343
    if ($sessionId && 'true' === api_get_setting('session.session_courses_read_only_mode')) {
3344
        $efv = new ExtraFieldValue('course');
3345
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3346
            api_get_course_int_id(),
3347
            'session_courses_read_only_mode'
3348
        );
3349
3350
        if (!empty($lockExrafieldField['value'])) {
3351
            return false;
3352
        }
3353
    }
3354
3355
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3356
    $session_visibility = api_get_session_visibility($sessionId);
3357
    $is_courseAdmin = api_is_course_admin();
3358
3359
    if (!$is_courseAdmin && $tutor) {
3360
        // If we also want to check if the user is a tutor...
3361
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3362
    }
3363
3364
    if (!$is_courseAdmin && $coach) {
3365
        // If we also want to check if the user is a coach...';
3366
        // Check if session visibility is read only for coaches.
3367
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3368
            $is_allowed_coach_to_edit = false;
3369
        }
3370
3371
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3372
            // Check if coach is allowed to edit a course.
3373
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3374
        }
3375
    }
3376
3377
    if (!$is_courseAdmin && $session_coach) {
3378
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3379
    }
3380
3381
    // Check if the student_view is enabled, and if so, if it is activated.
3382
    if ('true' === api_get_setting('student_view_enabled')) {
3383
        $studentView = api_is_student_view_active();
3384
        if (!empty($sessionId)) {
3385
            // Check if session visibility is read only for coaches.
3386
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3387
                $is_allowed_coach_to_edit = false;
3388
            }
3389
3390
            $is_allowed = false;
3391
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3392
                // Check if coach is allowed to edit a course.
3393
                $is_allowed = $is_allowed_coach_to_edit;
3394
            }
3395
            if ($check_student_view) {
3396
                $is_allowed = $is_allowed && false === $studentView;
3397
            }
3398
        } else {
3399
            $is_allowed = $is_courseAdmin;
3400
            if ($check_student_view) {
3401
                $is_allowed = $is_courseAdmin && false === $studentView;
3402
            }
3403
        }
3404
3405
        return $is_allowed;
3406
    } else {
3407
        return $is_courseAdmin;
3408
    }
3409
}
3410
3411
/**
3412
 * Returns true if user is a course coach of at least one course in session.
3413
 *
3414
 * @param int $sessionId
3415
 *
3416
 * @return bool
3417
 */
3418
function api_is_coach_of_course_in_session($sessionId)
3419
{
3420
    if (api_is_platform_admin()) {
3421
        return true;
3422
    }
3423
3424
    $userId = api_get_user_id();
3425
    $courseList = UserManager::get_courses_list_by_session(
3426
        $userId,
3427
        $sessionId
3428
    );
3429
3430
    // Session visibility.
3431
    $visibility = api_get_session_visibility(
3432
        $sessionId,
3433
        null,
3434
        false
3435
    );
3436
3437
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3438
        // Course Coach session visibility.
3439
        $blockedCourseCount = 0;
3440
        $closedVisibilityList = [
3441
            COURSE_VISIBILITY_CLOSED,
3442
            COURSE_VISIBILITY_HIDDEN,
3443
        ];
3444
3445
        foreach ($courseList as $course) {
3446
            // Checking session visibility
3447
            $sessionCourseVisibility = api_get_session_visibility(
3448
                $sessionId,
3449
                $course['real_id']
3450
            );
3451
3452
            $courseIsVisible = !in_array(
3453
                $course['visibility'],
3454
                $closedVisibilityList
3455
            );
3456
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3457
                $blockedCourseCount++;
3458
            }
3459
        }
3460
3461
        // If all courses are blocked then no show in the list.
3462
        if ($blockedCourseCount === count($courseList)) {
3463
            $visibility = SESSION_INVISIBLE;
3464
        } else {
3465
            $visibility = SESSION_VISIBLE;
3466
        }
3467
    }
3468
3469
    switch ($visibility) {
3470
        case SESSION_VISIBLE_READ_ONLY:
3471
        case SESSION_VISIBLE:
3472
        case SESSION_AVAILABLE:
3473
            return true;
3474
            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...
3475
        case SESSION_INVISIBLE:
3476
            return false;
3477
    }
3478
3479
    return false;
3480
}
3481
3482
/**
3483
 * Checks if a student can edit contents in a session depending
3484
 * on the session visibility.
3485
 *
3486
 * @param bool $tutor Whether to check if the user has the tutor role
3487
 * @param bool $coach Whether to check if the user has the coach role
3488
 *
3489
 * @return bool true: the user has the rights to edit, false: he does not
3490
 */
3491
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3492
{
3493
    if (api_is_allowed_to_edit($tutor, $coach)) {
3494
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3495
        return true;
3496
    } else {
3497
        $sessionId = api_get_session_id();
3498
3499
        if (0 == $sessionId) {
3500
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3501
            return true;
3502
        } else {
3503
            // I'm in a session and I'm a student
3504
            // Get the session visibility
3505
            $session_visibility = api_get_session_visibility($sessionId);
3506
            // if 5 the session is still available
3507
            switch ($session_visibility) {
3508
                case SESSION_VISIBLE_READ_ONLY: // 1
3509
                    return false;
3510
                case SESSION_VISIBLE:           // 2
3511
                    return true;
3512
                case SESSION_INVISIBLE:         // 3
3513
                    return false;
3514
                case SESSION_AVAILABLE:         //5
3515
                    return true;
3516
            }
3517
        }
3518
    }
3519
3520
    return false;
3521
}
3522
3523
/**
3524
 * Current user is anon?
3525
 *
3526
 * @return bool true if this user is anonymous, false otherwise
3527
 */
3528
function api_is_anonymous()
3529
{
3530
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED');
3531
}
3532
3533
/**
3534
 * Displays message "You are not allowed here..." and exits the entire script.
3535
 *
3536
 * @param bool $print_headers Whether to print headers (default = false -> does not print them)
3537
 * @param string $message
3538
 * @param int $responseCode
3539
 *
3540
 * @throws Exception
3541
 */
3542
function api_not_allowed(
3543
    $print_headers = false,
3544
    $message = null,
3545
    $responseCode = 0
3546
): never {
3547
    throw new NotAllowedException($message ?: 'You are not allowed', null, $responseCode);
3548
}
3549
3550
/**
3551
 * @param string $languageIsoCode
3552
 *
3553
 * @return string
3554
 */
3555
function languageToCountryIsoCode($languageIsoCode)
3556
{
3557
    $allow = ('true' === api_get_setting('language.language_flags_by_country'));
3558
3559
    // @todo save in DB
3560
    switch ($languageIsoCode) {
3561
        case 'ar':
3562
            $country = 'ae';
3563
            break;
3564
        case 'bs':
3565
            $country = 'ba';
3566
            break;
3567
        case 'ca':
3568
            $country = 'es';
3569
            if ($allow) {
3570
                $country = 'catalan';
3571
            }
3572
            break;
3573
        case 'cs':
3574
            $country = 'cz';
3575
            break;
3576
        case 'da':
3577
            $country = 'dk';
3578
            break;
3579
        case 'el':
3580
            $country = 'ae';
3581
            break;
3582
        case 'en':
3583
            $country = 'gb';
3584
            break;
3585
        case 'eu': // Euskera
3586
            $country = 'es';
3587
            if ($allow) {
3588
                $country = 'basque';
3589
            }
3590
            break;
3591
        case 'gl': // galego
3592
            $country = 'es';
3593
            if ($allow) {
3594
                $country = 'galician';
3595
            }
3596
            break;
3597
        case 'he':
3598
            $country = 'il';
3599
            break;
3600
        case 'ja':
3601
            $country = 'jp';
3602
            break;
3603
        case 'ka':
3604
            $country = 'ge';
3605
            break;
3606
        case 'ko':
3607
            $country = 'kr';
3608
            break;
3609
        case 'ms':
3610
            $country = 'my';
3611
            break;
3612
        case 'pt-BR':
3613
            $country = 'br';
3614
            break;
3615
        case 'qu':
3616
            $country = 'pe';
3617
            break;
3618
        case 'sl':
3619
            $country = 'si';
3620
            break;
3621
        case 'sv':
3622
            $country = 'se';
3623
            break;
3624
        case 'uk': // Ukraine
3625
            $country = 'ua';
3626
            break;
3627
        case 'zh-TW':
3628
        case 'zh':
3629
            $country = 'cn';
3630
            break;
3631
        default:
3632
            $country = $languageIsoCode;
3633
            break;
3634
    }
3635
    $country = strtolower($country);
3636
3637
    return $country;
3638
}
3639
3640
/**
3641
 * Returns a list of all the languages that are made available by the admin.
3642
 *
3643
 * @return array An array with all languages. Structure of the array is
3644
 *               array['name'] = An array with the name of every language
3645
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
3646
 */
3647
function api_get_languages()
3648
{
3649
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3650
    $sql = "SELECT * FROM $table WHERE available='1'
3651
            ORDER BY original_name ASC";
3652
    $result = Database::query($sql);
3653
    $languages = [];
3654
    while ($row = Database::fetch_assoc($result)) {
3655
        $languages[$row['isocode']] = $row['original_name'];
3656
    }
3657
3658
    return $languages;
3659
}
3660
3661
/**
3662
 * Returns the id (the database id) of a language.
3663
 *
3664
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
3665
 *
3666
 * @return int id of the language
3667
 */
3668
function api_get_language_id($language)
3669
{
3670
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3671
    if (empty($language)) {
3672
        return null;
3673
    }
3674
3675
    // We check the language by iscocode
3676
    $langInfo = api_get_language_from_iso($language);
3677
    if (null !== $langInfo && !empty($langInfo->getId())) {
3678
        return $langInfo->getId();
3679
    }
3680
3681
    $language = Database::escape_string($language);
3682
    $sql = "SELECT id FROM $tbl_language
3683
            WHERE english_name = '$language' LIMIT 1";
3684
    $result = Database::query($sql);
3685
    $row = Database::fetch_array($result);
3686
3687
    return $row['id'];
3688
}
3689
3690
/**
3691
 * Get the language information by its id.
3692
 *
3693
 * @param int $languageId
3694
 *
3695
 * @throws Exception
3696
 *
3697
 * @return array
3698
 */
3699
function api_get_language_info($languageId)
3700
{
3701
    if (empty($languageId)) {
3702
        return [];
3703
    }
3704
3705
    $language = Database::getManager()->find(Language::class, $languageId);
3706
3707
    if (!$language) {
3708
        return [];
3709
    }
3710
3711
    return [
3712
        'id' => $language->getId(),
3713
        'original_name' => $language->getOriginalName(),
3714
        'english_name' => $language->getEnglishName(),
3715
        'isocode' => $language->getIsocode(),
3716
        'available' => $language->getAvailable(),
3717
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
3718
    ];
3719
}
3720
3721
/**
3722
 * @param string $code
3723
 *
3724
 * @return Language
3725
 */
3726
function api_get_language_from_iso($code)
3727
{
3728
    $em = Database::getManager();
3729
3730
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
3731
}
3732
3733
/**
3734
 * Shortcut to ThemeHelper::getVisualTheme()
3735
 */
3736
function api_get_visual_theme(): string
3737
{
3738
    $themeHelper = Container::$container->get(ThemeHelper::class);
0 ignored issues
show
Bug introduced by
The method get() 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

3738
    /** @scrutinizer ignore-call */ 
3739
    $themeHelper = Container::$container->get(ThemeHelper::class);

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...
3739
3740
    return $themeHelper->getVisualTheme();
3741
}
3742
3743
/**
3744
 * Returns a list of CSS themes currently available in the CSS folder
3745
 * The folder must have a default.css file.
3746
 *
3747
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
3748
 *
3749
 * @return array list of themes directories from the css folder
3750
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
3751
 */
3752
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
3753
{
3754
    // This configuration value is set by the vchamilo plugin
3755
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
3756
3757
    $readCssFolder = function ($dir) use ($virtualTheme) {
3758
        $finder = new Finder();
3759
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
3760
        $list = [];
3761
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
3762
        foreach ($themes as $theme) {
3763
            $folder = $theme->getFilename();
3764
            // A theme folder is consider if there's a default.css file
3765
            if (!file_exists($theme->getPathname().'/default.css')) {
3766
                continue;
3767
            }
3768
            $name = ucwords(str_replace('_', ' ', $folder));
3769
            if ($folder == $virtualTheme) {
3770
                continue;
3771
            }
3772
            $list[$folder] = $name;
3773
        }
3774
3775
        return $list;
3776
    };
3777
3778
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
3779
    $list = $readCssFolder($dir);
3780
3781
    if (!empty($virtualTheme)) {
3782
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
3783
        if ($getOnlyThemeFromVirtualInstance) {
3784
            return $newList;
3785
        }
3786
        $list = $list + $newList;
3787
        asort($list);
3788
    }
3789
3790
    return $list;
3791
}
3792
3793
/**
3794
 * Find the largest sort value in a given user_course_category
3795
 * This function is used when we are moving a course to a different category
3796
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
3797
 *
3798
 * @param int $courseCategoryId the id of the user_course_category
3799
 * @param int $userId
3800
 *
3801
 * @return int the value of the highest sort of the user_course_category
3802
 */
3803
function api_max_sort_value($courseCategoryId, $userId)
3804
{
3805
    $user = api_get_user_entity($userId);
3806
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
3807
3808
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
3809
}
3810
3811
/**
3812
 * Transforms a number of seconds in hh:mm:ss format.
3813
 *
3814
 * @author Julian Prud'homme
3815
 *
3816
 * @param int    $seconds      number of seconds
3817
 * @param string $space
3818
 * @param bool   $showSeconds
3819
 * @param bool   $roundMinutes
3820
 *
3821
 * @return string the formatted time
3822
 */
3823
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
3824
{
3825
    // $seconds = -1 means that we have wrong data in the db.
3826
    if (-1 == $seconds) {
3827
        return
3828
            get_lang('Unknown').
3829
            Display::getMdiIcon(
3830
                ActionIcon::INFORMATION,
3831
                'ch-tool-icon',
3832
                'align: absmiddle; hspace: 3px',
3833
                ICON_SIZE_SMALL,
3834
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.')
3835
            );
3836
    }
3837
3838
    // How many hours ?
3839
    $hours = floor($seconds / 3600);
3840
3841
    // How many minutes ?
3842
    $min = floor(($seconds - ($hours * 3600)) / 60);
3843
3844
    if ($roundMinutes) {
3845
        if ($min >= 45) {
3846
            $min = 45;
3847
        }
3848
3849
        if ($min >= 30 && $min <= 44) {
3850
            $min = 30;
3851
        }
3852
3853
        if ($min >= 15 && $min <= 29) {
3854
            $min = 15;
3855
        }
3856
3857
        if ($min >= 0 && $min <= 14) {
3858
            $min = 0;
3859
        }
3860
    }
3861
3862
    // How many seconds
3863
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
3864
3865
    if ($hours < 10) {
3866
        $hours = "0$hours";
3867
    }
3868
3869
    if ($sec < 10) {
3870
        $sec = "0$sec";
3871
    }
3872
3873
    if ($min < 10) {
3874
        $min = "0$min";
3875
    }
3876
3877
    $seconds = '';
3878
    if ($showSeconds) {
3879
        $seconds = $space.$sec;
3880
    }
3881
3882
    return $hours.$space.$min.$seconds;
3883
}
3884
3885
/**
3886
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3887
 * The return value is based on the platform administrator's setting
3888
 * "Administration > Configuration settings > Security > Permissions for new directories".
3889
 *
3890
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
3891
 */
3892
function api_get_permissions_for_new_directories()
3893
{
3894
    static $permissions;
3895
    if (!isset($permissions)) {
3896
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
3897
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
3898
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
3899
    }
3900
3901
    return $permissions;
3902
}
3903
3904
/**
3905
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3906
 * The return value is based on the platform administrator's setting
3907
 * "Administration > Configuration settings > Security > Permissions for new files".
3908
 *
3909
 * @return int returns the permissions in the format
3910
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
3911
 */
3912
function api_get_permissions_for_new_files()
3913
{
3914
    static $permissions;
3915
    if (!isset($permissions)) {
3916
        $permissions = trim(api_get_setting('permissions_for_new_files'));
3917
        // The default value 0666 is according to that in the platform
3918
        // administration panel after fresh system installation.
3919
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
3920
    }
3921
3922
    return $permissions;
3923
}
3924
3925
/**
3926
 * Deletes a file, or a folder and its contents.
3927
 *
3928
 * @author      Aidan Lister <[email protected]>
3929
 *
3930
 * @version     1.0.3
3931
 *
3932
 * @param string $dirname Directory to delete
3933
 * @param       bool     Deletes only the content or not
3934
 * @param bool $strict if one folder/file fails stop the loop
3935
 *
3936
 * @return bool Returns TRUE on success, FALSE on failure
3937
 *
3938
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
3939
 *
3940
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
3941
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
3942
 */
3943
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
3944
{
3945
    $res = true;
3946
    // A sanity check.
3947
    if (!file_exists($dirname)) {
3948
        return false;
3949
    }
3950
    $php_errormsg = '';
3951
    // Simple delete for a file.
3952
    if (is_file($dirname) || is_link($dirname)) {
3953
        $res = unlink($dirname);
3954
        if (false === $res) {
3955
            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);
3956
        }
3957
3958
        return $res;
3959
    }
3960
3961
    // Loop through the folder.
3962
    $dir = dir($dirname);
3963
    // A sanity check.
3964
    $is_object_dir = is_object($dir);
3965
    if ($is_object_dir) {
3966
        while (false !== $entry = $dir->read()) {
3967
            // Skip pointers.
3968
            if ('.' == $entry || '..' == $entry) {
3969
                continue;
3970
            }
3971
3972
            // Recurse.
3973
            if ($strict) {
3974
                $result = rmdirr("$dirname/$entry");
3975
                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...
3976
                    $res = false;
3977
                    break;
3978
                }
3979
            } else {
3980
                rmdirr("$dirname/$entry");
3981
            }
3982
        }
3983
    }
3984
3985
    // Clean up.
3986
    if ($is_object_dir) {
3987
        $dir->close();
3988
    }
3989
3990
    if (false == $delete_only_content_in_folder) {
3991
        $res = rmdir($dirname);
3992
        if (false === $res) {
3993
            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);
3994
        }
3995
    }
3996
3997
    return $res;
3998
}
3999
4000
// TODO: This function is to be simplified. File access modes to be implemented.
4001
/**
4002
 * function adapted from a php.net comment
4003
 * copy recursively a folder.
4004
 *
4005
 * @param the source folder
4006
 * @param the dest folder
4007
 * @param an array of excluded file_name (without extension)
4008
 * @param copied_files the returned array of copied files
4009
 * @param string $source
4010
 * @param string $dest
4011
 */
4012
function copyr($source, $dest, $exclude = [], $copied_files = [])
4013
{
4014
    if (empty($dest)) {
4015
        return false;
4016
    }
4017
    // Simple copy for a file
4018
    if (is_file($source)) {
4019
        $path_info = pathinfo($source);
4020
        if (!in_array($path_info['filename'], $exclude)) {
4021
            copy($source, $dest);
4022
        }
4023
4024
        return true;
4025
    } elseif (!is_dir($source)) {
4026
        //then source is not a dir nor a file, return
4027
        return false;
4028
    }
4029
4030
    // Make destination directory.
4031
    if (!is_dir($dest)) {
4032
        mkdir($dest, api_get_permissions_for_new_directories());
4033
    }
4034
4035
    // Loop through the folder.
4036
    $dir = dir($source);
4037
    while (false !== $entry = $dir->read()) {
4038
        // Skip pointers
4039
        if ('.' == $entry || '..' == $entry) {
4040
            continue;
4041
        }
4042
4043
        // Deep copy directories.
4044
        if ($dest !== "$source/$entry") {
4045
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4046
        }
4047
    }
4048
    // Clean up.
4049
    $dir->close();
4050
4051
    return true;
4052
}
4053
4054
/**
4055
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4056
 * Documentation header to be added here.
4057
 *
4058
 * @param string $pathname
4059
 * @param string $base_path_document
4060
 * @param int    $session_id
4061
 *
4062
 * @return mixed True if directory already exists, false if a file already exists at
4063
 *               the destination and null if everything goes according to plan
4064
 */
4065
function copy_folder_course_session(
4066
    $pathname,
4067
    $base_path_document,
4068
    $session_id,
4069
    $course_info,
4070
    $document,
4071
    $source_course_id
4072
) {
4073
    $table = Database::get_course_table(TABLE_DOCUMENT);
4074
    $session_id = intval($session_id);
4075
    $source_course_id = intval($source_course_id);
4076
4077
    // Check whether directory already exists.
4078
    if (is_dir($pathname) || empty($pathname)) {
4079
        return true;
4080
    }
4081
4082
    // Ensure that a file with the same name does not already exist.
4083
    if (is_file($pathname)) {
4084
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4085
4086
        return false;
4087
    }
4088
4089
    $course_id = $course_info['real_id'];
4090
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4091
    $new_pathname = $base_path_document;
4092
    $path = '';
4093
4094
    foreach ($folders as $folder) {
4095
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4096
        $path .= DIRECTORY_SEPARATOR.$folder;
4097
4098
        if (!file_exists($new_pathname)) {
4099
            $path = Database::escape_string($path);
4100
4101
            $sql = "SELECT * FROM $table
4102
                    WHERE
4103
                        c_id = $source_course_id AND
4104
                        path = '$path' AND
4105
                        filetype = 'folder' AND
4106
                        session_id = '$session_id'";
4107
            $rs1 = Database::query($sql);
4108
            $num_rows = Database::num_rows($rs1);
4109
4110
            if (0 == $num_rows) {
4111
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4112
4113
                // Insert new folder with destination session_id.
4114
                $params = [
4115
                    'c_id' => $course_id,
4116
                    'path' => $path,
4117
                    'comment' => $document->comment,
4118
                    'title' => basename($new_pathname),
4119
                    'filetype' => 'folder',
4120
                    'size' => '0',
4121
                    'session_id' => $session_id,
4122
                ];
4123
                Database::insert($table, $params);
4124
            }
4125
        }
4126
    } // en foreach
4127
}
4128
4129
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4130
/**
4131
 * @param string $path
4132
 */
4133
function api_chmod_R($path, $filemode)
4134
{
4135
    if (!is_dir($path)) {
4136
        return chmod($path, $filemode);
4137
    }
4138
4139
    $handler = opendir($path);
4140
    while ($file = readdir($handler)) {
4141
        if ('.' != $file && '..' != $file) {
4142
            $fullpath = "$path/$file";
4143
            if (!is_dir($fullpath)) {
4144
                if (!chmod($fullpath, $filemode)) {
4145
                    return false;
4146
                }
4147
            } else {
4148
                if (!api_chmod_R($fullpath, $filemode)) {
4149
                    return false;
4150
                }
4151
            }
4152
        }
4153
    }
4154
4155
    closedir($handler);
4156
4157
    return chmod($path, $filemode);
4158
}
4159
4160
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4161
/**
4162
 * Parse info file format. (e.g: file.info).
4163
 *
4164
 * Files should use an ini-like format to specify values.
4165
 * White-space generally doesn't matter, except inside values.
4166
 * e.g.
4167
 *
4168
 * @verbatim
4169
 *   key = value
4170
 *   key = "value"
4171
 *   key = 'value'
4172
 *   key = "multi-line
4173
 *
4174
 *   value"
4175
 *   key = 'multi-line
4176
 *
4177
 *   value'
4178
 *   key
4179
 *   =
4180
 *   'value'
4181
 * @endverbatim
4182
 *
4183
 * Arrays are created using a GET-like syntax:
4184
 *
4185
 * @verbatim
4186
 *   key[] = "numeric array"
4187
 *   key[index] = "associative array"
4188
 *   key[index][] = "nested numeric array"
4189
 *   key[index][index] = "nested associative array"
4190
 * @endverbatim
4191
 *
4192
 * PHP constants are substituted in, but only when used as the entire value:
4193
 *
4194
 * Comments should start with a semi-colon at the beginning of a line.
4195
 *
4196
 * This function is NOT for placing arbitrary module-specific settings. Use
4197
 * variable_get() and variable_set() for that.
4198
 *
4199
 * Information stored in the module.info file:
4200
 * - name: The real name of the module for display purposes.
4201
 * - description: A brief description of the module.
4202
 * - dependencies: An array of shortnames of other modules this module depends on.
4203
 * - package: The name of the package of modules this module belongs to.
4204
 *
4205
 * Example of .info file:
4206
 * <code>
4207
 * @verbatim
4208
 *   name = Forum
4209
 *   description = Enables threaded discussions about general topics.
4210
 *   dependencies[] = taxonomy
4211
 *   dependencies[] = comment
4212
 *   package = Core - optional
4213
 *   version = VERSION
4214
 * @endverbatim
4215
 * </code>
4216
 *
4217
 * @param string $filename
4218
 *                         The file we are parsing. Accepts file with relative or absolute path.
4219
 *
4220
 * @return
4221
 *   The info array
4222
 */
4223
function api_parse_info_file($filename)
4224
{
4225
    $info = [];
4226
4227
    if (!file_exists($filename)) {
4228
        return $info;
4229
    }
4230
4231
    $data = file_get_contents($filename);
4232
    if (preg_match_all('
4233
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4234
        ((?:
4235
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4236
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4237
        )+?)
4238
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4239
        (?:
4240
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4241
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4242
          ([^\r\n]*?)                   # Non-quoted string
4243
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4244
        @msx', $data, $matches, PREG_SET_ORDER)) {
4245
        $key = $value1 = $value2 = $value3 = '';
4246
        foreach ($matches as $match) {
4247
            // Fetch the key and value string.
4248
            $i = 0;
4249
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4250
                $$var = isset($match[++$i]) ? $match[$i] : '';
4251
            }
4252
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4253
4254
            // Parse array syntax.
4255
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4256
            $last = array_pop($keys);
4257
            $parent = &$info;
4258
4259
            // Create nested arrays.
4260
            foreach ($keys as $key) {
4261
                if ('' == $key) {
4262
                    $key = count($parent);
4263
                }
4264
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4265
                    $parent[$key] = [];
4266
                }
4267
                $parent = &$parent[$key];
4268
            }
4269
4270
            // Handle PHP constants.
4271
            if (defined($value)) {
4272
                $value = constant($value);
4273
            }
4274
4275
            // Insert actual value.
4276
            if ('' == $last) {
4277
                $last = count($parent);
4278
            }
4279
            $parent[$last] = $value;
4280
        }
4281
    }
4282
4283
    return $info;
4284
}
4285
4286
/**
4287
 * Gets Chamilo version from the configuration files.
4288
 *
4289
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4290
 */
4291
function api_get_version()
4292
{
4293
    return (string) api_get_configuration_value('system_version');
4294
}
4295
4296
/**
4297
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4298
 *
4299
 * @return string
4300
 */
4301
function api_get_software_name()
4302
{
4303
    $name = api_get_configuration_value('software_name');
4304
    if (!empty($name)) {
4305
        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...
4306
    } else {
4307
        return 'Chamilo';
4308
    }
4309
}
4310
4311
function api_get_status_list()
4312
{
4313
    $list = [];
4314
    // Table of status
4315
    $list[COURSEMANAGER] = 'teacher'; // 1
4316
    $list[SESSIONADMIN] = 'session_admin'; // 3
4317
    $list[DRH] = 'drh'; // 4
4318
    $list[STUDENT] = 'user'; // 5
4319
    $list[ANONYMOUS] = 'anonymous'; // 6
4320
    $list[INVITEE] = 'invited'; // 20
4321
4322
    return $list;
4323
}
4324
4325
/**
4326
 * Checks whether status given in parameter exists in the platform.
4327
 *
4328
 * @param mixed the status (can be either int either string)
4329
 *
4330
 * @return bool if the status exists, else returns false
4331
 */
4332
function api_status_exists($status_asked)
4333
{
4334
    $list = api_get_status_list();
4335
4336
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4337
}
4338
4339
/**
4340
 * Checks whether status given in parameter exists in the platform. The function
4341
 * returns the status ID or false if it does not exist, but given the fact there
4342
 * is no "0" status, the return value can be checked against
4343
 * if(api_status_key()) to know if it exists.
4344
 *
4345
 * @param   mixed   The status (can be either int or string)
4346
 *
4347
 * @return mixed Status ID if exists, false otherwise
4348
 */
4349
function api_status_key($status)
4350
{
4351
    $list = api_get_status_list();
4352
4353
    return isset($list[$status]) ? $status : array_search($status, $list);
4354
}
4355
4356
/**
4357
 * Gets the status langvars list.
4358
 *
4359
 * @return string[] the list of status with their translations
4360
 */
4361
function api_get_status_langvars()
4362
{
4363
    return [
4364
        COURSEMANAGER => get_lang('Teacher'),
4365
        SESSIONADMIN => get_lang('SessionsAdmin'),
4366
        DRH => get_lang('Human Resources Manager'),
4367
        STUDENT => get_lang('Learner'),
4368
        ANONYMOUS => get_lang('Anonymous'),
4369
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4370
        INVITEE => get_lang('Invited'),
4371
    ];
4372
}
4373
4374
/**
4375
 * The function that retrieves all the possible settings for a certain config setting.
4376
 *
4377
 * @author Patrick Cool <[email protected]>, Ghent University
4378
 */
4379
function api_get_settings_options($var)
4380
{
4381
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4382
    $var = Database::escape_string($var);
4383
    $sql = "SELECT * FROM $table_settings_options
4384
            WHERE variable = '$var'
4385
            ORDER BY id";
4386
    $result = Database::query($sql);
4387
    $settings_options_array = [];
4388
    while ($row = Database::fetch_assoc($result)) {
4389
        $settings_options_array[] = $row;
4390
    }
4391
4392
    return $settings_options_array;
4393
}
4394
4395
/**
4396
 * @param array $params
4397
 */
4398
function api_set_setting_option($params)
4399
{
4400
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4401
    if (empty($params['id'])) {
4402
        Database::insert($table, $params);
4403
    } else {
4404
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4405
    }
4406
}
4407
4408
/**
4409
 * @param array $params
4410
 */
4411
function api_set_setting_simple($params)
4412
{
4413
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4414
    $url_id = api_get_current_access_url_id();
4415
4416
    if (empty($params['id'])) {
4417
        $params['access_url'] = $url_id;
4418
        Database::insert($table, $params);
4419
    } else {
4420
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4421
    }
4422
}
4423
4424
/**
4425
 * @param int $id
4426
 */
4427
function api_delete_setting_option($id)
4428
{
4429
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4430
    if (!empty($id)) {
4431
        Database::delete($table, ['id = ? ' => $id]);
4432
    }
4433
}
4434
4435
/**
4436
 * Sets a platform configuration setting to a given value.
4437
 *
4438
 * @param string    The variable we want to update
4439
 * @param string    The value we want to record
4440
 * @param string    The sub-variable if any (in most cases, this will remain null)
4441
 * @param string    The category if any (in most cases, this will remain null)
4442
 * @param int       The access_url for which this parameter is valid
4443
 * @param string $cat
4444
 *
4445
 * @return bool|null
4446
 */
4447
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
4448
{
4449
    if (empty($var)) {
4450
        return false;
4451
    }
4452
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4453
    $var = Database::escape_string($var);
4454
    $value = Database::escape_string($value);
4455
    $access_url = (int) $access_url;
4456
    if (empty($access_url)) {
4457
        $access_url = 1;
4458
    }
4459
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
4460
    if (!empty($subvar)) {
4461
        $subvar = Database::escape_string($subvar);
4462
        $select .= " AND subkey = '$subvar'";
4463
    }
4464
    if (!empty($cat)) {
4465
        $cat = Database::escape_string($cat);
4466
        $select .= " AND category = '$cat'";
4467
    }
4468
    if ($access_url > 1) {
4469
        $select .= " AND access_url = $access_url";
4470
    } else {
4471
        $select .= " AND access_url = 1 ";
4472
    }
4473
4474
    $res = Database::query($select);
4475
    if (Database::num_rows($res) > 0) {
4476
        // Found item for this access_url.
4477
        $row = Database::fetch_array($res);
4478
        $sql = "UPDATE $t_settings SET selected_value = '$value'
4479
                WHERE id = ".$row['id'];
4480
        Database::query($sql);
4481
    } else {
4482
        // Item not found for this access_url, we have to check if it exist with access_url = 1
4483
        $select = "SELECT * FROM $t_settings
4484
                   WHERE variable = '$var' AND access_url = 1 ";
4485
        // Just in case
4486
        if (1 == $access_url) {
4487
            if (!empty($subvar)) {
4488
                $select .= " AND subkey = '$subvar'";
4489
            }
4490
            if (!empty($cat)) {
4491
                $select .= " AND category = '$cat'";
4492
            }
4493
            $res = Database::query($select);
4494
            if (Database::num_rows($res) > 0) {
4495
                // We have a setting for access_url 1, but none for the current one, so create one.
4496
                $row = Database::fetch_array($res);
4497
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
4498
                        VALUES
4499
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4500
                    "'".$row['type']."','".$row['category']."',".
4501
                    "'$value','".$row['title']."',".
4502
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4503
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
4504
                Database::query($insert);
4505
            } else {
4506
                // Such a setting does not exist.
4507
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
4508
            }
4509
        } else {
4510
            // Other access url.
4511
            if (!empty($subvar)) {
4512
                $select .= " AND subkey = '$subvar'";
4513
            }
4514
            if (!empty($cat)) {
4515
                $select .= " AND category = '$cat'";
4516
            }
4517
            $res = Database::query($select);
4518
4519
            if (Database::num_rows($res) > 0) {
4520
                // We have a setting for access_url 1, but none for the current one, so create one.
4521
                $row = Database::fetch_array($res);
4522
                if (1 == $row['access_url_changeable']) {
4523
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
4524
                            ('".$row['variable']."',".
4525
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4526
                        "'".$row['type']."','".$row['category']."',".
4527
                        "'$value','".$row['title']."',".
4528
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
4529
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4530
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
4531
                    Database::query($insert);
4532
                }
4533
            } else { // Such a setting does not exist.
4534
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
4535
            }
4536
        }
4537
    }
4538
}
4539
4540
/**
4541
 * Sets a whole category of settings to one specific value.
4542
 *
4543
 * @param string    Category
4544
 * @param string    Value
4545
 * @param int       Access URL. Optional. Defaults to 1
4546
 * @param array     Optional array of filters on field type
4547
 * @param string $category
4548
 * @param string $value
4549
 *
4550
 * @return bool
4551
 */
4552
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
4553
{
4554
    if (empty($category)) {
4555
        return false;
4556
    }
4557
    $category = Database::escape_string($category);
4558
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4559
    $access_url = (int) $access_url;
4560
    if (empty($access_url)) {
4561
        $access_url = 1;
4562
    }
4563
    if (isset($value)) {
4564
        $value = Database::escape_string($value);
4565
        $sql = "UPDATE $t_s SET selected_value = '$value'
4566
                WHERE category = '$category' AND access_url = $access_url";
4567
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4568
            $sql .= " AND ( ";
4569
            $i = 0;
4570
            foreach ($fieldtype as $type) {
4571
                if ($i > 0) {
4572
                    $sql .= ' OR ';
4573
                }
4574
                $type = Database::escape_string($type);
4575
                $sql .= " type='".$type."' ";
4576
                $i++;
4577
            }
4578
            $sql .= ")";
4579
        }
4580
        $res = Database::query($sql);
4581
4582
        return false !== $res;
4583
    } else {
4584
        $sql = "UPDATE $t_s SET selected_value = NULL
4585
                WHERE category = '$category' AND access_url = $access_url";
4586
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4587
            $sql .= " AND ( ";
4588
            $i = 0;
4589
            foreach ($fieldtype as $type) {
4590
                if ($i > 0) {
4591
                    $sql .= ' OR ';
4592
                }
4593
                $type = Database::escape_string($type);
4594
                $sql .= " type='".$type."' ";
4595
                $i++;
4596
            }
4597
            $sql .= ")";
4598
        }
4599
        $res = Database::query($sql);
4600
4601
        return false !== $res;
4602
    }
4603
}
4604
4605
/**
4606
 * Gets all available access urls in an array (as in the database).
4607
 *
4608
 * @return array An array of database records
4609
 */
4610
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
4611
{
4612
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4613
    $from = (int) $from;
4614
    $to = (int) $to;
4615
    $order = Database::escape_string($order);
4616
    $direction = Database::escape_string($direction);
4617
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
4618
    $sql = "SELECT id, url, description, active, created_by, tms
4619
            FROM $table
4620
            ORDER BY `$order` $direction
4621
            LIMIT $to OFFSET $from";
4622
    $res = Database::query($sql);
4623
4624
    return Database::store_result($res);
4625
}
4626
4627
/**
4628
 * Gets the access url info in an array.
4629
 *
4630
 * @param int  $id            Id of the access url
4631
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
4632
 *
4633
 * @return array All the info (url, description, active, created_by, tms)
4634
 *               from the access_url table
4635
 *
4636
 * @author Julio Montoya
4637
 */
4638
function api_get_access_url($id, $returnDefault = true)
4639
{
4640
    static $staticResult;
4641
    $id = (int) $id;
4642
4643
    if (isset($staticResult[$id])) {
4644
        $result = $staticResult[$id];
4645
    } else {
4646
        // Calling the Database:: library dont work this is handmade.
4647
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4648
        $sql = "SELECT url, description, active, created_by, tms
4649
                FROM $table_access_url WHERE id = '$id' ";
4650
        $res = Database::query($sql);
4651
        $result = @Database::fetch_array($res);
4652
        $staticResult[$id] = $result;
4653
    }
4654
4655
    // If the result url is 'http://localhost/' (the default) and the root_web
4656
    // (=current url) is different, and the $id is = 1 (which might mean
4657
    // api_get_current_access_url_id() returned 1 by default), then return the
4658
    // root_web setting instead of the current URL
4659
    // This is provided as an option to avoid breaking the storage of URL-specific
4660
    // homepages in home/localhost/
4661
    if (1 === $id && false === $returnDefault) {
4662
        $currentUrl = api_get_current_access_url_id();
4663
        // only do this if we are on the main URL (=1), otherwise we could get
4664
        // information on another URL instead of the one asked as parameter
4665
        if (1 === $currentUrl) {
4666
            $rootWeb = api_get_path(WEB_PATH);
4667
            $default = AccessUrl::DEFAULT_ACCESS_URL;
4668
            if ($result['url'] === $default && $rootWeb != $default) {
4669
                $result['url'] = $rootWeb;
4670
            }
4671
        }
4672
    }
4673
4674
    return $result;
4675
}
4676
4677
/**
4678
 * Gets all the current settings for a specific access url.
4679
 *
4680
 * @param string    The category, if any, that we want to get
4681
 * @param string    Whether we want a simple list (display a category) or
4682
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
4683
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
4684
 *
4685
 * @return array Array of database results for the current settings of the current access URL
4686
 */
4687
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
4688
{
4689
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4690
    $access_url = (int) $access_url;
4691
    $where_condition = '';
4692
    if (1 == $url_changeable) {
4693
        $where_condition = " AND access_url_changeable= '1' ";
4694
    }
4695
    if (empty($access_url) || -1 == $access_url) {
4696
        $access_url = 1;
4697
    }
4698
    $sql = "SELECT * FROM $table
4699
            WHERE access_url = $access_url  $where_condition ";
4700
4701
    if (!empty($cat)) {
4702
        $cat = Database::escape_string($cat);
4703
        $sql .= " AND category='$cat' ";
4704
    }
4705
    if ('group' == $ordering) {
4706
        $sql .= " ORDER BY id ASC";
4707
    } else {
4708
        $sql .= " ORDER BY 1,2 ASC";
4709
    }
4710
    $result = Database::query($sql);
4711
    if (null === $result) {
4712
        $result = [];
4713
        return $result;
4714
    }
4715
    $result = Database::store_result($result, 'ASSOC');
4716
4717
    return $result;
4718
}
4719
4720
/**
4721
 * @param string $value       The value we want to record
4722
 * @param string $variable    The variable name we want to insert
4723
 * @param string $subKey      The subkey for the variable we want to insert
4724
 * @param string $type        The type for the variable we want to insert
4725
 * @param string $category    The category for the variable we want to insert
4726
 * @param string $title       The title
4727
 * @param string $comment     The comment
4728
 * @param string $scope       The scope
4729
 * @param string $subKeyText  The subkey text
4730
 * @param int    $accessUrlId The access_url for which this parameter is valid
4731
 * @param int    $visibility  The changeability of this setting for non-master urls
4732
 *
4733
 * @return int The setting ID
4734
 */
4735
function api_add_setting(
4736
    $value,
4737
    $variable,
4738
    $subKey = '',
4739
    $type = 'textfield',
4740
    $category = '',
4741
    $title = '',
4742
    $comment = '',
4743
    $scope = '',
4744
    $subKeyText = '',
4745
    $accessUrlId = 1,
4746
    $visibility = 0
4747
) {
4748
    $em = Database::getManager();
4749
4750
    $settingRepo = $em->getRepository(SettingsCurrent::class);
4751
    $accessUrlId = (int) $accessUrlId ?: 1;
4752
4753
    if (is_array($value)) {
4754
        $value = serialize($value);
4755
    } else {
4756
        $value = trim($value);
4757
    }
4758
4759
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
4760
4761
    if (!empty($subKey)) {
4762
        $criteria['subkey'] = $subKey;
4763
    }
4764
4765
    // Check if this variable doesn't exist already
4766
    /** @var SettingsCurrent $setting */
4767
    $setting = $settingRepo->findOneBy($criteria);
4768
4769
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
4770
        $setting->setSelectedValue($value);
4771
4772
        $em->persist($setting);
4773
        $em->flush();
4774
4775
        return $setting->getId();
4776
    }
4777
4778
    // Item not found for this access_url, we have to check if the whole thing is missing
4779
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
4780
    $setting = new SettingsCurrent();
4781
    $url = api_get_url_entity();
4782
4783
    $setting
4784
        ->setVariable($variable)
4785
        ->setSelectedValue($value)
4786
        ->setType($type)
4787
        ->setCategory($category)
4788
        ->setSubkey($subKey)
4789
        ->setTitle($title)
4790
        ->setComment($comment)
4791
        ->setScope($scope)
4792
        ->setSubkeytext($subKeyText)
4793
        ->setUrl(api_get_url_entity())
4794
        ->setAccessUrlChangeable($visibility);
4795
4796
    $em->persist($setting);
4797
    $em->flush();
4798
4799
    return $setting->getId();
4800
}
4801
4802
/**
4803
 * Checks wether a user can or can't view the contents of a course.
4804
 *
4805
 * @deprecated use CourseManager::is_user_subscribed_in_course
4806
 *
4807
 * @param int $userid User id or NULL to get it from $_SESSION
4808
 * @param int $cid    course id to check whether the user is allowed
4809
 *
4810
 * @return bool
4811
 */
4812
function api_is_course_visible_for_user($userid = null, $cid = null)
4813
{
4814
    if (null === $userid) {
4815
        $userid = api_get_user_id();
4816
    }
4817
    if (empty($userid) || strval(intval($userid)) != $userid) {
4818
        if (api_is_anonymous()) {
4819
            $userid = api_get_anonymous_id();
4820
        } else {
4821
            return false;
4822
        }
4823
    }
4824
    $cid = Database::escape_string($cid);
4825
4826
    $courseInfo = api_get_course_info($cid);
4827
    $courseId = $courseInfo['real_id'];
4828
    $is_platformAdmin = api_is_platform_admin();
4829
4830
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
4831
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
4832
4833
    $sql = "SELECT
4834
                $course_cat_table.code AS category_code,
4835
                $course_table.visibility,
4836
                $course_table.code,
4837
                $course_cat_table.code
4838
            FROM $course_table
4839
            LEFT JOIN $course_cat_table
4840
                ON $course_table.category_id = $course_cat_table.id
4841
            WHERE
4842
                $course_table.code = '$cid'
4843
            LIMIT 1";
4844
4845
    $result = Database::query($sql);
4846
4847
    if (Database::num_rows($result) > 0) {
4848
        $visibility = Database::fetch_array($result);
4849
        $visibility = $visibility['visibility'];
4850
    } else {
4851
        $visibility = 0;
4852
    }
4853
    // Shortcut permissions in case the visibility is "open to the world".
4854
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
4855
        return true;
4856
    }
4857
4858
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4859
4860
    $sql = "SELECT
4861
                is_tutor, status
4862
            FROM $tbl_course_user
4863
            WHERE
4864
                user_id  = '$userid' AND
4865
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
4866
                c_id = $courseId
4867
            LIMIT 1";
4868
4869
    $result = Database::query($sql);
4870
4871
    if (Database::num_rows($result) > 0) {
4872
        // This user has got a recorded state for this course.
4873
        $cuData = Database::fetch_array($result);
4874
        $is_courseMember = true;
4875
        $is_courseAdmin = (1 == $cuData['status']);
4876
    }
4877
4878
    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...
4879
        // This user has no status related to this course.
4880
        // Is it the session coach or the session admin?
4881
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4882
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4883
        $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4884
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4885
4886
        $sql = "SELECT sru_2.user_id AS session_admin_id, sru_1.user_id AS session_coach_id
4887
                FROM $tbl_session AS s
4888
                INNER JOIN $tblSessionRelUser sru_1
4889
                ON (sru_1.session_id = s.id AND sru_1.relation_type = ".SessionEntity::GENERAL_COACH.")
4890
                INNER JOIN $tblSessionRelUser sru_2
4891
                ON (sru_2.session_id = s.id AND sru_2.relation_type = ".SessionEntity::SESSION_ADMIN.")
4892
                INNER JOIN $tbl_session_course src
4893
                ON (src.session_id = s.id AND src.c_id = $courseId)";
4894
4895
        $result = Database::query($sql);
4896
        $row = Database::store_result($result);
4897
        $sessionAdminsId = array_column($row, 'session_admin_id');
4898
        $sessionCoachesId = array_column($row, 'session_coach_id');
4899
4900
        if (in_array($userid, $sessionCoachesId)) {
4901
            $is_courseMember = true;
4902
            $is_courseAdmin = false;
4903
        } elseif (in_array($userid, $sessionAdminsId)) {
4904
            $is_courseMember = false;
4905
            $is_courseAdmin = false;
4906
        } else {
4907
            // Check if the current user is the course coach.
4908
            $sql = "SELECT 1
4909
                    FROM $tbl_session_course
4910
                    WHERE session_rel_course.c_id = '$courseId'
4911
                    AND session_rel_course.id_coach = '$userid'
4912
                    LIMIT 1";
4913
4914
            $result = Database::query($sql);
4915
4916
            //if ($row = Database::fetch_array($result)) {
4917
            if (Database::num_rows($result) > 0) {
4918
                $is_courseMember = true;
4919
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4920
4921
                $sql = "SELECT status FROM $tbl_user
4922
                        WHERE id = $userid
4923
                        LIMIT 1";
4924
4925
                $result = Database::query($sql);
4926
4927
                if (1 == Database::result($result, 0, 0)) {
4928
                    $is_courseAdmin = true;
4929
                } else {
4930
                    $is_courseAdmin = false;
4931
                }
4932
            } else {
4933
                // Check if the user is a student is this session.
4934
                $sql = "SELECT  id
4935
                        FROM $tbl_session_course_user
4936
                        WHERE
4937
                            user_id  = '$userid' AND
4938
                            c_id = '$courseId'
4939
                        LIMIT 1";
4940
4941
                if (Database::num_rows($result) > 0) {
4942
                    // This user haa got a recorded state for this course.
4943
                    while ($row = Database::fetch_array($result)) {
4944
                        $is_courseMember = true;
4945
                        $is_courseAdmin = false;
4946
                    }
4947
                }
4948
            }
4949
        }
4950
    }
4951
4952
    switch ($visibility) {
4953
        case Course::OPEN_WORLD:
4954
            return true;
4955
        case Course::OPEN_PLATFORM:
4956
            return isset($userid);
4957
        case Course::REGISTERED:
4958
        case Course::CLOSED:
4959
            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...
4960
        case Course::HIDDEN:
4961
            return $is_platformAdmin;
4962
    }
4963
4964
    return false;
4965
}
4966
4967
/**
4968
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
4969
 *
4970
 * @param string the tool of the element
4971
 * @param int the element id in database
4972
 * @param int the session_id to compare with element session id
4973
 *
4974
 * @return bool true if the element is in the session, false else
4975
 */
4976
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
4977
{
4978
    if (is_null($session_id)) {
4979
        $session_id = api_get_session_id();
4980
    }
4981
4982
    $element_id = (int) $element_id;
4983
4984
    if (empty($element_id)) {
4985
        return false;
4986
    }
4987
4988
    // Get information to build query depending of the tool.
4989
    switch ($tool) {
4990
        case TOOL_SURVEY:
4991
            $table_tool = Database::get_course_table(TABLE_SURVEY);
4992
            $key_field = 'survey_id';
4993
            break;
4994
        case TOOL_ANNOUNCEMENT:
4995
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
4996
            $key_field = 'id';
4997
            break;
4998
        case TOOL_AGENDA:
4999
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5000
            $key_field = 'id';
5001
            break;
5002
        case TOOL_GROUP:
5003
            $table_tool = Database::get_course_table(TABLE_GROUP);
5004
            $key_field = 'id';
5005
            break;
5006
        default:
5007
            return false;
5008
    }
5009
    $course_id = api_get_course_int_id();
5010
5011
    $sql = "SELECT session_id FROM $table_tool
5012
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5013
    $rs = Database::query($sql);
5014
    if ($element_session_id = Database::result($rs, 0, 0)) {
5015
        if ($element_session_id == intval($session_id)) {
5016
            // The element belongs to the session.
5017
            return true;
5018
        }
5019
    }
5020
5021
    return false;
5022
}
5023
5024
/**
5025
 * Replaces "forbidden" characters in a filename string.
5026
 *
5027
 * @param string $filename
5028
 * @param bool   $treat_spaces_as_hyphens
5029
 *
5030
 * @return string
5031
 */
5032
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5033
{
5034
    // Some non-properly encoded file names can cause the whole file to be
5035
    // skipped when uploaded. Avoid this by detecting the encoding and
5036
    // converting to UTF-8, setting the source as ASCII (a reasonably
5037
    // limited characters set) if nothing could be found (BT#
5038
    $encoding = api_detect_encoding($filename);
5039
    if (empty($encoding)) {
5040
        $encoding = 'ASCII';
5041
        if (!api_is_valid_ascii($filename)) {
5042
            // try iconv and try non standard ASCII a.k.a CP437
5043
            // see BT#15022
5044
            if (function_exists('iconv')) {
5045
                $result = iconv('CP437', 'UTF-8', $filename);
5046
                if (api_is_valid_utf8($result)) {
5047
                    $filename = $result;
5048
                    $encoding = 'UTF-8';
5049
                }
5050
            }
5051
        }
5052
    }
5053
5054
    $filename = api_to_system_encoding($filename, $encoding);
5055
5056
    $url = URLify::filter(
5057
        $filename,
5058
        250,
5059
        '',
5060
        true,
5061
        false,
5062
        false
5063
    );
5064
5065
    // Replace multiple dots at the end.
5066
    $regex = "/\.+$/";
5067
5068
    return preg_replace($regex, '', $url);
5069
}
5070
5071
/**
5072
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5073
 *
5074
 * @author Ivan Tcholakov, 28-JUN-2006.
5075
 */
5076
function api_request_uri()
5077
{
5078
    if (!empty($_SERVER['REQUEST_URI'])) {
5079
        return $_SERVER['REQUEST_URI'];
5080
    }
5081
    $uri = $_SERVER['SCRIPT_NAME'];
5082
    if (!empty($_SERVER['QUERY_STRING'])) {
5083
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5084
    }
5085
    $_SERVER['REQUEST_URI'] = $uri;
5086
5087
    return $uri;
5088
}
5089
5090
/**
5091
 * Gets the current access_url id of the Chamilo Platform.
5092
 *
5093
 * @return int access_url_id of the current Chamilo Installation
5094
 *
5095
 * @author Julio Montoya <[email protected]>
5096
 * @throws Exception
5097
 */
5098
function api_get_current_access_url_id(): int
5099
{
5100
    if (false === api_get_multiple_access_url()) {
5101
        return 1;
5102
    }
5103
5104
    static $id;
5105
    if (!empty($id)) {
5106
        return $id;
5107
    }
5108
5109
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5110
    $path = Database::escape_string(api_get_path(WEB_PATH));
5111
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5112
    $result = Database::query($sql);
5113
    if (Database::num_rows($result) > 0) {
5114
        $id = Database::result($result, 0, 0);
5115
        if (false === $id) {
5116
            return -1;
5117
        }
5118
5119
        return (int) $id;
5120
    }
5121
5122
    $id = 1;
5123
5124
    //if the url in WEB_PATH was not found, it can only mean that there is
5125
    // either a configuration problem or the first URL has not been defined yet
5126
    // (by default it is http://localhost/). Thus the more sensible thing we can
5127
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5128
    return 1;
5129
}
5130
5131
/**
5132
 * Gets the registered urls from a given user id.
5133
 *
5134
 * @author Julio Montoya <[email protected]>
5135
 *
5136
 * @param int $user_id
5137
 *
5138
 * @return array
5139
 */
5140
function api_get_access_url_from_user($user_id)
5141
{
5142
    $user_id = (int) $user_id;
5143
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5144
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5145
    $sql = "SELECT access_url_id
5146
            FROM $table_url_rel_user url_rel_user
5147
            INNER JOIN $table_url u
5148
            ON (url_rel_user.access_url_id = u.id)
5149
            WHERE user_id = ".$user_id;
5150
    $result = Database::query($sql);
5151
    $list = [];
5152
    while ($row = Database::fetch_assoc($result)) {
5153
        $list[] = $row['access_url_id'];
5154
    }
5155
5156
    return $list;
5157
}
5158
5159
/**
5160
 * Checks whether the curent user is in a group or not.
5161
 *
5162
 * @param string        The group id - optional (takes it from session if not given)
5163
 * @param string        The course code - optional (no additional check by course if course code is not given)
5164
 *
5165
 * @return bool
5166
 *
5167
 * @author Ivan Tcholakov
5168
 */
5169
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5170
{
5171
    if (!empty($courseCodeParam)) {
5172
        $courseCode = api_get_course_id();
5173
        if (!empty($courseCode)) {
5174
            if ($courseCodeParam != $courseCode) {
5175
                return false;
5176
            }
5177
        } else {
5178
            return false;
5179
        }
5180
    }
5181
5182
    $groupId = api_get_group_id();
5183
5184
    if (isset($groupId) && '' != $groupId) {
5185
        if (!empty($groupIdParam)) {
5186
            return $groupIdParam == $groupId;
5187
        } else {
5188
            return true;
5189
        }
5190
    }
5191
5192
    return false;
5193
}
5194
5195
/**
5196
 * Checks whether a secret key is valid.
5197
 *
5198
 * @param string $original_key_secret - secret key from (webservice) client
5199
 * @param string $security_key        - security key from Chamilo
5200
 *
5201
 * @return bool - true if secret key is valid, false otherwise
5202
 */
5203
function api_is_valid_secret_key($original_key_secret, $security_key)
5204
{
5205
    if (empty($original_key_secret) || empty($security_key)) {
5206
        return false;
5207
    }
5208
5209
    return (string) $original_key_secret === sha1($security_key);
5210
}
5211
5212
/**
5213
 * Checks whether the server's operating system is Windows (TM).
5214
 *
5215
 * @return bool - true if the operating system is Windows, false otherwise
5216
 */
5217
function api_is_windows_os()
5218
{
5219
    if (function_exists('php_uname')) {
5220
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5221
        // We expect that this function will always work for Chamilo 1.8.x.
5222
        $os = php_uname();
5223
    }
5224
    // The following methods are not needed, but let them stay, just in case.
5225
    elseif (isset($_ENV['OS'])) {
5226
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5227
        $os = $_ENV['OS'];
5228
    } elseif (defined('PHP_OS')) {
5229
        // PHP_OS means on which OS PHP was compiled, this is why
5230
        // using PHP_OS is the last choice for detection.
5231
        $os = PHP_OS;
5232
    } else {
5233
        return false;
5234
    }
5235
5236
    return 'win' == strtolower(substr((string) $os, 0, 3));
5237
}
5238
5239
/**
5240
 * This function informs whether the sent request is XMLHttpRequest.
5241
 */
5242
function api_is_xml_http_request()
5243
{
5244
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5245
}
5246
5247
/**
5248
 * Returns a list of Chamilo's tools or
5249
 * checks whether a given identificator is a valid Chamilo's tool.
5250
 *
5251
 * @author Isaac flores paz
5252
 *
5253
 * @param string The tool name to filter
5254
 *
5255
 * @return mixed Filtered string or array
5256
 */
5257
function api_get_tools_lists($my_tool = null)
5258
{
5259
    $tools_list = [
5260
        TOOL_DOCUMENT,
5261
        TOOL_THUMBNAIL,
5262
        TOOL_HOTPOTATOES,
5263
        TOOL_CALENDAR_EVENT,
5264
        TOOL_LINK,
5265
        TOOL_COURSE_DESCRIPTION,
5266
        TOOL_SEARCH,
5267
        TOOL_LEARNPATH,
5268
        TOOL_ANNOUNCEMENT,
5269
        TOOL_FORUM,
5270
        TOOL_THREAD,
5271
        TOOL_POST,
5272
        TOOL_DROPBOX,
5273
        TOOL_QUIZ,
5274
        TOOL_USER,
5275
        TOOL_GROUP,
5276
        TOOL_BLOGS,
5277
        TOOL_CHAT,
5278
        TOOL_STUDENTPUBLICATION,
5279
        TOOL_TRACKING,
5280
        TOOL_HOMEPAGE_LINK,
5281
        TOOL_COURSE_SETTING,
5282
        TOOL_BACKUP,
5283
        TOOL_COPY_COURSE_CONTENT,
5284
        TOOL_RECYCLE_COURSE,
5285
        TOOL_COURSE_HOMEPAGE,
5286
        TOOL_COURSE_RIGHTS_OVERVIEW,
5287
        TOOL_UPLOAD,
5288
        TOOL_COURSE_MAINTENANCE,
5289
        TOOL_SURVEY,
5290
        //TOOL_WIKI,
5291
        TOOL_GLOSSARY,
5292
        TOOL_GRADEBOOK,
5293
        TOOL_NOTEBOOK,
5294
        TOOL_ATTENDANCE,
5295
        TOOL_COURSE_PROGRESS,
5296
    ];
5297
    if (empty($my_tool)) {
5298
        return $tools_list;
5299
    }
5300
5301
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5302
}
5303
5304
/**
5305
 * Checks whether we already approved the last version term and condition.
5306
 *
5307
 * @param int user id
5308
 *
5309
 * @return bool true if we pass false otherwise
5310
 */
5311
function api_check_term_condition($userId)
5312
{
5313
    if ('true' === api_get_setting('allow_terms_conditions')) {
5314
        // Check if exists terms and conditions
5315
        if (0 == LegalManager::count()) {
5316
            return true;
5317
        }
5318
5319
        $extraFieldValue = new ExtraFieldValue('user');
5320
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5321
            $userId,
5322
            'legal_accept'
5323
        );
5324
5325
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5326
            $result = $data['value'];
5327
            $user_conditions = explode(':', $result);
5328
            $version = $user_conditions[0];
5329
            $langId = $user_conditions[1];
5330
            $realVersion = LegalManager::get_last_version($langId);
5331
5332
            return $version >= $realVersion;
5333
        }
5334
5335
        return false;
5336
    }
5337
5338
    return false;
5339
}
5340
5341
/**
5342
 * Gets all information of a tool into course.
5343
 *
5344
 * @param int The tool id
5345
 *
5346
 * @return array
5347
 */
5348
function api_get_tool_information_by_name($name)
5349
{
5350
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5351
    $course_id = api_get_course_int_id();
5352
5353
    $sql = "SELECT id FROM tool
5354
            WHERE title = '".Database::escape_string($name)."' ";
5355
    $rs = Database::query($sql);
5356
    $data = Database::fetch_array($rs);
5357
    if ($data) {
5358
        $tool = $data['id'];
5359
        $sql = "SELECT * FROM $t_tool
5360
                WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
5361
        $rs = Database::query($sql);
5362
5363
        return Database::fetch_assoc($rs);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Database::fetch_assoc($rs) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
5364
    }
5365
5366
    return [];
5367
}
5368
5369
/**
5370
 * Function used to protect a "global" admin script.
5371
 * The function blocks access when the user has no global platform admin rights.
5372
 * Global admins are the admins that are registered in the main.admin table
5373
 * AND the users who have access to the "principal" portal.
5374
 * That means that there is a record in the main.access_url_rel_user table
5375
 * with his user id and the access_url_id=1.
5376
 *
5377
 * @author Julio Montoya
5378
 *
5379
 * @param int $user_id
5380
 *
5381
 * @return bool
5382
 */
5383
function api_is_global_platform_admin($user_id = null)
5384
{
5385
    $user_id = (int) $user_id;
5386
    if (empty($user_id)) {
5387
        $user_id = api_get_user_id();
5388
    }
5389
    if (api_is_platform_admin_by_id($user_id)) {
5390
        $urlList = api_get_access_url_from_user($user_id);
5391
        // The admin is registered in the first "main" site with access_url_id = 1
5392
        if (in_array(1, $urlList)) {
5393
            return true;
5394
        }
5395
    }
5396
5397
    return false;
5398
}
5399
5400
/**
5401
 * @param int  $admin_id_to_check
5402
 * @param int  $userId
5403
 * @param bool $allow_session_admin
5404
 *
5405
 * @return bool
5406
 */
5407
function api_global_admin_can_edit_admin(
5408
    $admin_id_to_check,
5409
    $userId = 0,
5410
    $allow_session_admin = false
5411
) {
5412
    if (empty($userId)) {
5413
        $userId = api_get_user_id();
5414
    }
5415
5416
    $iam_a_global_admin = api_is_global_platform_admin($userId);
5417
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
5418
5419
    if ($iam_a_global_admin) {
5420
        // Global admin can edit everything
5421
        return true;
5422
    }
5423
5424
    // If i'm a simple admin
5425
    $is_platform_admin = api_is_platform_admin_by_id($userId);
5426
5427
    if ($allow_session_admin && !$is_platform_admin) {
5428
        $user = api_get_user_entity($userId);
5429
        $is_platform_admin = $user->hasRole('ROLE_SESSION_MANAGER');
5430
    }
5431
5432
    if ($is_platform_admin) {
5433
        if ($user_is_global_admin) {
5434
            return false;
5435
        } else {
5436
            return true;
5437
        }
5438
    }
5439
5440
    return false;
5441
}
5442
5443
/**
5444
 * @param int  $admin_id_to_check
5445
 * @param int  $userId
5446
 * @param bool $allow_session_admin
5447
 *
5448
 * @return bool|null
5449
 */
5450
function api_protect_super_admin($admin_id_to_check, $userId = null, $allow_session_admin = false)
5451
{
5452
    if (api_global_admin_can_edit_admin($admin_id_to_check, $userId, $allow_session_admin)) {
5453
        return true;
5454
    } else {
5455
        api_not_allowed();
5456
    }
5457
}
5458
5459
/**
5460
 * Function used to protect a global admin script.
5461
 * The function blocks access when the user has no global platform admin rights.
5462
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
5463
 *
5464
 * @author Julio Montoya
5465
 */
5466
function api_protect_global_admin_script()
5467
{
5468
    if (!api_is_global_platform_admin()) {
5469
        api_not_allowed();
5470
5471
        return false;
5472
    }
5473
5474
    return true;
5475
}
5476
5477
/**
5478
 * Check browser support for specific file types or features
5479
 * This function checks if the user's browser supports a file format or given
5480
 * feature, or returns the current browser and major version when
5481
 * $format=check_browser. Only a limited number of formats and features are
5482
 * checked by this method. Make sure you check its definition first.
5483
 *
5484
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
5485
 *
5486
 * @deprecated
5487
 *
5488
 * @return bool or return text array if $format=check_browser
5489
 *
5490
 * @author Juan Carlos Raña Trabado
5491
 */
5492
function api_browser_support($format = '')
5493
{
5494
    return true;
5495
5496
    $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...
5497
    $current_browser = $browser->getBrowser();
5498
    $a_versiontemp = explode('.', $browser->getVersion());
5499
    $current_majorver = $a_versiontemp[0];
5500
5501
    static $result;
5502
5503
    if (isset($result[$format])) {
5504
        return $result[$format];
5505
    }
5506
5507
    // Native svg support
5508
    if ('svg' == $format) {
5509
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5510
            ('Firefox' == $current_browser && $current_majorver > 1) ||
5511
            ('Safari' == $current_browser && $current_majorver >= 4) ||
5512
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
5513
            ('Opera' == $current_browser && $current_majorver >= 9)
5514
        ) {
5515
            $result[$format] = true;
5516
5517
            return true;
5518
        } else {
5519
            $result[$format] = false;
5520
5521
            return false;
5522
        }
5523
    } elseif ('pdf' == $format) {
5524
        // native pdf support
5525
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
5526
            $result[$format] = true;
5527
5528
            return true;
5529
        } else {
5530
            $result[$format] = false;
5531
5532
            return false;
5533
        }
5534
    } elseif ('tif' == $format || 'tiff' == $format) {
5535
        //native tif support
5536
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5537
            $result[$format] = true;
5538
5539
            return true;
5540
        } else {
5541
            $result[$format] = false;
5542
5543
            return false;
5544
        }
5545
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
5546
        //native ogg, ogv,oga support
5547
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
5548
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
5549
            ('Opera' == $current_browser && $current_majorver >= 9)) {
5550
            $result[$format] = true;
5551
5552
            return true;
5553
        } else {
5554
            $result[$format] = false;
5555
5556
            return false;
5557
        }
5558
    } elseif ('mpg' == $format || 'mpeg' == $format) {
5559
        //native mpg support
5560
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
5561
            $result[$format] = true;
5562
5563
            return true;
5564
        } else {
5565
            $result[$format] = false;
5566
5567
            return false;
5568
        }
5569
    } elseif ('mp4' == $format) {
5570
        //native mp4 support (TODO: Android, iPhone)
5571
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
5572
            $result[$format] = true;
5573
5574
            return true;
5575
        } else {
5576
            $result[$format] = false;
5577
5578
            return false;
5579
        }
5580
    } elseif ('mov' == $format) {
5581
        //native mov support( TODO:check iPhone)
5582
        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...
5583
            $result[$format] = true;
5584
5585
            return true;
5586
        } else {
5587
            $result[$format] = false;
5588
5589
            return false;
5590
        }
5591
    } elseif ('avi' == $format) {
5592
        //native avi support
5593
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5594
            $result[$format] = true;
5595
5596
            return true;
5597
        } else {
5598
            $result[$format] = false;
5599
5600
            return false;
5601
        }
5602
    } elseif ('wmv' == $format) {
5603
        //native wmv support
5604
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5605
            $result[$format] = true;
5606
5607
            return true;
5608
        } else {
5609
            $result[$format] = false;
5610
5611
            return false;
5612
        }
5613
    } elseif ('webm' == $format) {
5614
        //native webm support (TODO:check IE9, Chrome9, Android)
5615
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
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
        ) {
5621
            $result[$format] = true;
5622
5623
            return true;
5624
        } else {
5625
            $result[$format] = false;
5626
5627
            return false;
5628
        }
5629
    } elseif ('wav' == $format) {
5630
        //native wav support (only some codecs !)
5631
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5632
            ('Safari' == $current_browser && $current_majorver >= 5) ||
5633
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5634
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5635
            ('Chrome' == $current_browser && $current_majorver > 9) ||
5636
            'Android' == $current_browser ||
5637
            'iPhone' == $current_browser
5638
        ) {
5639
            $result[$format] = true;
5640
5641
            return true;
5642
        } else {
5643
            $result[$format] = false;
5644
5645
            return false;
5646
        }
5647
    } elseif ('mid' == $format || 'kar' == $format) {
5648
        //native midi support (TODO:check Android)
5649
        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...
5650
            $result[$format] = true;
5651
5652
            return true;
5653
        } else {
5654
            $result[$format] = false;
5655
5656
            return false;
5657
        }
5658
    } elseif ('wma' == $format) {
5659
        //native wma support
5660
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5661
            $result[$format] = true;
5662
5663
            return true;
5664
        } else {
5665
            $result[$format] = false;
5666
5667
            return false;
5668
        }
5669
    } elseif ('au' == $format) {
5670
        //native au support
5671
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5672
            $result[$format] = true;
5673
5674
            return true;
5675
        } else {
5676
            $result[$format] = false;
5677
5678
            return false;
5679
        }
5680
    } elseif ('mp3' == $format) {
5681
        //native mp3 support (TODO:check Android, iPhone)
5682
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
5683
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
5684
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5685
            'Android' == $current_browser ||
5686
            'iPhone' == $current_browser ||
5687
            'Firefox' == $current_browser
5688
        ) {
5689
            $result[$format] = true;
5690
5691
            return true;
5692
        } else {
5693
            $result[$format] = false;
5694
5695
            return false;
5696
        }
5697
    } elseif ('autocapitalize' == $format) {
5698
        // Help avoiding showing the autocapitalize option if the browser doesn't
5699
        // support it: this attribute is against the HTML5 standard
5700
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
5701
            return true;
5702
        } else {
5703
            return false;
5704
        }
5705
    } elseif ("check_browser" == $format) {
5706
        $array_check_browser = [$current_browser, $current_majorver];
5707
5708
        return $array_check_browser;
5709
    } else {
5710
        $result[$format] = false;
5711
5712
        return false;
5713
    }
5714
}
5715
5716
/**
5717
 * This function checks if exist path and file browscap.ini
5718
 * In order for this to work, your browscap configuration setting in php.ini
5719
 * must point to the correct location of the browscap.ini file on your system
5720
 * http://php.net/manual/en/function.get-browser.php.
5721
 *
5722
 * @return bool
5723
 *
5724
 * @author Juan Carlos Raña Trabado
5725
 */
5726
function api_check_browscap()
5727
{
5728
    $setting = ini_get('browscap');
5729
    if ($setting) {
5730
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
5731
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
5732
            return true;
5733
        }
5734
    }
5735
5736
    return false;
5737
}
5738
5739
/**
5740
 * Returns the <script> HTML tag.
5741
 */
5742
function api_get_js($file)
5743
{
5744
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
5745
}
5746
5747
function api_get_build_js($file)
5748
{
5749
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
5750
}
5751
5752
function api_get_build_css($file, $media = 'screen')
5753
{
5754
    return '<link
5755
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5756
}
5757
5758
/**
5759
 * Returns the <script> HTML tag.
5760
 *
5761
 * @return string
5762
 */
5763
function api_get_asset($file)
5764
{
5765
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
5766
}
5767
5768
/**
5769
 * Returns the <script> HTML tag.
5770
 *
5771
 * @param string $file
5772
 * @param string $media
5773
 *
5774
 * @return string
5775
 */
5776
function api_get_css_asset($file, $media = 'screen')
5777
{
5778
    return '<link
5779
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"
5780
        rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5781
}
5782
5783
/**
5784
 * Returns the <link> HTML tag.
5785
 *
5786
 * @param string $file
5787
 * @param string $media
5788
 */
5789
function api_get_css($file, $media = 'screen')
5790
{
5791
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5792
}
5793
5794
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false, $returnFileLocation = false)
5795
{
5796
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
5797
5798
    if ($returnOnlyPath) {
5799
        if ($returnFileLocation) {
5800
            return api_get_path(SYS_PUBLIC_PATH).'build/css/bootstrap.css';
5801
        }
5802
5803
        return $url;
5804
    }
5805
5806
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
5807
}
5808
5809
/**
5810
 * Returns the js header to include the jquery library.
5811
 */
5812
function api_get_jquery_js()
5813
{
5814
    return api_get_asset('jquery/jquery.min.js');
5815
}
5816
5817
/**
5818
 * Returns the jquery path.
5819
 *
5820
 * @return string
5821
 */
5822
function api_get_jquery_web_path()
5823
{
5824
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
5825
}
5826
5827
/**
5828
 * @return string
5829
 */
5830
function api_get_jquery_ui_js_web_path()
5831
{
5832
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
5833
}
5834
5835
/**
5836
 * @return string
5837
 */
5838
function api_get_jquery_ui_css_web_path()
5839
{
5840
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
5841
}
5842
5843
/**
5844
 * Returns the jquery-ui library js headers.
5845
 *
5846
 * @return string html tags
5847
 */
5848
function api_get_jquery_ui_js()
5849
{
5850
    $libraries = [];
5851
5852
    return api_get_jquery_libraries_js($libraries);
5853
}
5854
5855
function api_get_jqgrid_js()
5856
{
5857
    return api_get_build_css('legacy_free-jqgrid.css').PHP_EOL
5858
        .api_get_build_js('legacy_free-jqgrid.js');
5859
}
5860
5861
/**
5862
 * Returns the jquery library js and css headers.
5863
 *
5864
 * @param   array   list of jquery libraries supported jquery-ui
5865
 * @param   bool    add the jquery library
5866
 *
5867
 * @return string html tags
5868
 */
5869
function api_get_jquery_libraries_js($libraries)
5870
{
5871
    $js = '';
5872
5873
    //Document multiple upload funcionality
5874
    if (in_array('jquery-uploadzs', $libraries)) {
5875
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
5876
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
5877
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
5878
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
5879
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
5880
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
5881
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
5882
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
5883
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
5884
5885
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
5886
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
5887
    }
5888
5889
    // jquery datepicker
5890
    if (in_array('datepicker', $libraries)) {
5891
        $languaje = 'en-GB';
5892
        $platform_isocode = strtolower(api_get_language_isocode());
5893
5894
        $datapicker_langs = [
5895
            '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',
5896
        ];
5897
        if (in_array($platform_isocode, $datapicker_langs)) {
5898
            $languaje = $platform_isocode;
5899
        }
5900
5901
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
5902
        $script = '<script>
5903
        $(function(){
5904
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
5905
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
5906
        });
5907
        </script>
5908
        ';
5909
        $js .= $script;
5910
    }
5911
5912
    return $js;
5913
}
5914
5915
/**
5916
 * Returns the URL to the course or session, removing the complexity of the URL
5917
 * building piece by piece.
5918
 *
5919
 * This function relies on api_get_course_info()
5920
 *
5921
 * @param int $courseId  The course code - optional (takes it from context if not given)
5922
 * @param int $sessionId The session ID  - optional (takes it from context if not given)
5923
 * @param int $groupId   The group ID - optional (takes it from context if not given)
5924
 *
5925
 * @return string The URL to a course, a session, or empty string if nothing works
5926
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
5927
 *
5928
 * @author  Julio Montoya
5929
 */
5930
function api_get_course_url($courseId = null, $sessionId = null, $groupId = null)
5931
{
5932
    $url = '';
5933
    // If courseCode not set, get context or []
5934
    if (empty($courseId)) {
5935
        $courseId = api_get_course_int_id();
5936
    }
5937
5938
    // If sessionId not set, get context or 0
5939
    if (empty($sessionId)) {
5940
        $sessionId = api_get_session_id();
5941
    }
5942
5943
    // If groupId not set, get context or 0
5944
    if (empty($groupId)) {
5945
        $groupId = api_get_group_id();
5946
    }
5947
5948
    // Build the URL
5949
    if (!empty($courseId)) {
5950
        $webCourseHome = '/course/'.$courseId.'/home';
5951
        // directory not empty, so we do have a course
5952
        $url = $webCourseHome.'?sid='.$sessionId.'&gid='.$groupId;
5953
    } else {
5954
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
5955
            // if the course was unset and the session was set, send directly to the session
5956
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
5957
        }
5958
    }
5959
5960
    // if not valid combination was found, return an empty string
5961
    return $url;
5962
}
5963
5964
/**
5965
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
5966
 */
5967
function api_get_multiple_access_url(): bool
5968
{
5969
    global $_configuration;
5970
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
5971
        return true;
5972
    }
5973
5974
    return false;
5975
}
5976
5977
function api_is_multiple_url_enabled(): bool
5978
{
5979
    return api_get_multiple_access_url();
5980
}
5981
5982
/**
5983
 * Returns a md5 unique id.
5984
 *
5985
 * @todo add more parameters
5986
 */
5987
function api_get_unique_id()
5988
{
5989
    return md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
5990
}
5991
5992
/**
5993
 * @param int Course id
5994
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
5995
 * @param int the item id (tool id, exercise id, lp id)
5996
 *
5997
 * @return bool
5998
 */
5999
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6000
{
6001
    if (api_is_platform_admin()) {
6002
        return false;
6003
    }
6004
    if ('true' === api_get_setting('gradebook_locking_enabled')) {
6005
        if (empty($course_code)) {
6006
            $course_code = api_get_course_id();
6007
        }
6008
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6009
        $item_id = (int) $item_id;
6010
        $link_type = (int) $link_type;
6011
        $course_code = Database::escape_string($course_code);
6012
        $sql = "SELECT locked FROM $table
6013
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6014
        $result = Database::query($sql);
6015
        if (Database::num_rows($result)) {
6016
            return true;
6017
        }
6018
    }
6019
6020
    return false;
6021
}
6022
6023
/**
6024
 * Blocks a page if the item was added in a gradebook.
6025
 *
6026
 * @param int       exercise id, work id, thread id,
6027
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6028
 * see gradebook/lib/be/linkfactory
6029
 * @param string    course code
6030
 *
6031
 * @return false|null
6032
 */
6033
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6034
{
6035
    if (api_is_platform_admin()) {
6036
        return false;
6037
    }
6038
6039
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6040
        $message = Display::return_message(
6041
            get_lang(
6042
                '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.'
6043
            ),
6044
            'warning'
6045
        );
6046
        api_not_allowed(true, $message);
6047
    }
6048
}
6049
6050
/**
6051
 * Checks the PHP version installed is enough to run Chamilo.
6052
 *
6053
 * @param string Include path (used to load the error page)
6054
 */
6055
function api_check_php_version()
6056
{
6057
    if (!function_exists('version_compare') ||
6058
        version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')
6059
    ) {
6060
        throw new Exception('Wrong PHP version');
6061
    }
6062
}
6063
6064
/**
6065
 * Checks whether the Archive directory is present and writeable. If not,
6066
 * prints a warning message.
6067
 */
6068
function api_check_archive_dir()
6069
{
6070
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6071
        $message = Display::return_message(
6072
            get_lang(
6073
                'The var/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'
6074
            ),
6075
            'warning'
6076
        );
6077
        api_not_allowed(true, $message);
6078
    }
6079
}
6080
6081
/**
6082
 * Returns an array of global configuration settings which should be ignored
6083
 * when printing the configuration settings screens.
6084
 *
6085
 * @return array Array of strings, each identifying one of the excluded settings
6086
 */
6087
function api_get_locked_settings()
6088
{
6089
    return [
6090
        'permanently_remove_deleted_files',
6091
        'account_valid_duration',
6092
        'service_ppt2lp',
6093
        'wcag_anysurfer_public_pages',
6094
        'upload_extensions_list_type',
6095
        'upload_extensions_blacklist',
6096
        'upload_extensions_whitelist',
6097
        'upload_extensions_skip',
6098
        'upload_extensions_replace_by',
6099
        'hide_dltt_markup',
6100
        'split_users_upload_directory',
6101
        'permissions_for_new_directories',
6102
        'permissions_for_new_files',
6103
        'platform_charset',
6104
        'ldap_description',
6105
        'cas_activate',
6106
        'cas_server',
6107
        'cas_server_uri',
6108
        'cas_port',
6109
        'cas_protocol',
6110
        'cas_add_user_activate',
6111
        'update_user_info_cas_with_ldap',
6112
        'languagePriority1',
6113
        'languagePriority2',
6114
        'languagePriority3',
6115
        'languagePriority4',
6116
        'login_is_email',
6117
        'chamilo_database_version',
6118
    ];
6119
}
6120
6121
/**
6122
 * Guess the real ip for register in the database, even in reverse proxy cases.
6123
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6124
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6125
 * Note: the result of this function is not SQL-safe. Please escape it before
6126
 * inserting in a database.
6127
 *
6128
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6129
 *
6130
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6131
 *
6132
 * @version CEV CHANGE 24APR2012
6133
 * @throws RuntimeException
6134
 */
6135
function api_get_real_ip(): string
6136
{
6137
    if ('cli' === PHP_SAPI) {
6138
        $ip = '127.0.0.1';
6139
    } else {
6140
        $ip = trim($_SERVER['REMOTE_ADDR']);
6141
        if (empty($ip)) {
6142
            throw new RuntimeException("Unable to retrieve remote IP address.");
6143
        }
6144
    }
6145
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6146
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6147
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6148
        } else {
6149
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6150
        }
6151
        $ip = trim($ip1);
6152
    }
6153
6154
    return $ip;
6155
}
6156
6157
/**
6158
 * Checks whether an IP is included inside an IP range.
6159
 *
6160
 * @param string IP address
6161
 * @param string IP range
6162
 * @param string $ip
6163
 *
6164
 * @return bool True if IP is in the range, false otherwise
6165
 *
6166
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6167
 * @author Yannick Warnier for improvements and managment of multiple ranges
6168
 *
6169
 * @todo check for IPv6 support
6170
 */
6171
function api_check_ip_in_range($ip, $range)
6172
{
6173
    if (empty($ip) or empty($range)) {
6174
        return false;
6175
    }
6176
    $ip_ip = ip2long($ip);
6177
    // divide range param into array of elements
6178
    if (false !== strpos($range, ',')) {
6179
        $ranges = explode(',', $range);
6180
    } else {
6181
        $ranges = [$range];
6182
    }
6183
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6184
        $range = trim($range);
6185
        if (empty($range)) {
6186
            continue;
6187
        }
6188
        if (false === strpos($range, '/')) {
6189
            if (0 === strcmp($ip, $range)) {
6190
                return true; // there is a direct IP match, return OK
6191
            }
6192
            continue; //otherwise, get to the next range
6193
        }
6194
        // the range contains a "/", so analyse completely
6195
        [$net, $mask] = explode("/", $range);
6196
6197
        $ip_net = ip2long($net);
6198
        // mask binary magic
6199
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6200
6201
        $ip_ip_net = $ip_ip & $ip_mask;
6202
        if ($ip_ip_net == $ip_net) {
6203
            return true;
6204
        }
6205
    }
6206
6207
    return false;
6208
}
6209
6210
function api_check_user_access_to_legal($courseInfo)
6211
{
6212
    if (empty($courseInfo)) {
6213
        return false;
6214
    }
6215
6216
    $visibility = (int) $courseInfo['visibility'];
6217
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6218
6219
    return
6220
        in_array($visibility, $visibilityList) ||
6221
        api_is_drh() ||
6222
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
6223
}
6224
6225
/**
6226
 * Checks if the global chat is enabled or not.
6227
 *
6228
 * @return bool
6229
 */
6230
function api_is_global_chat_enabled()
6231
{
6232
    return
6233
        !api_is_anonymous() &&
6234
        'true' === api_get_setting('allow_global_chat') &&
6235
        'true' === api_get_setting('allow_social_tool');
6236
}
6237
6238
/**
6239
 * @param int   $item_id
6240
 * @param int   $tool_id
6241
 * @param int   $group_id   id
6242
 * @param array $courseInfo
6243
 * @param int   $sessionId
6244
 * @param int   $userId
6245
 *
6246
 * @deprecated
6247
 */
6248
function api_set_default_visibility(
6249
    $item_id,
6250
    $tool_id,
6251
    $group_id = 0,
6252
    $courseInfo = [],
6253
    $sessionId = 0,
6254
    $userId = 0
6255
) {
6256
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6257
    $courseId = $courseInfo['real_id'];
6258
    $courseCode = $courseInfo['code'];
6259
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6260
    $userId = empty($userId) ? api_get_user_id() : $userId;
6261
6262
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6263
    if (is_null($group_id)) {
6264
        $group_id = 0;
6265
    } else {
6266
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6267
    }
6268
6269
    $groupInfo = [];
6270
    if (!empty($group_id)) {
6271
        $groupInfo = GroupManager::get_group_properties($group_id);
6272
    }
6273
    $original_tool_id = $tool_id;
6274
6275
    switch ($tool_id) {
6276
        case TOOL_LINK:
6277
        case TOOL_LINK_CATEGORY:
6278
            $tool_id = 'links';
6279
            break;
6280
        case TOOL_DOCUMENT:
6281
            $tool_id = 'documents';
6282
            break;
6283
        case TOOL_LEARNPATH:
6284
            $tool_id = 'learning';
6285
            break;
6286
        case TOOL_ANNOUNCEMENT:
6287
            $tool_id = 'announcements';
6288
            break;
6289
        case TOOL_FORUM:
6290
        case TOOL_FORUM_CATEGORY:
6291
        case TOOL_FORUM_THREAD:
6292
            $tool_id = 'forums';
6293
            break;
6294
        case TOOL_QUIZ:
6295
            $tool_id = 'quiz';
6296
            break;
6297
    }
6298
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6299
6300
    if (isset($setting[$tool_id])) {
6301
        $visibility = 'invisible';
6302
        if ('true' === $setting[$tool_id]) {
6303
            $visibility = 'visible';
6304
        }
6305
6306
        // Read the portal and course default visibility
6307
        if ('documents' === $tool_id) {
6308
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6309
        }
6310
6311
        // Fixes default visibility for tests
6312
        switch ($original_tool_id) {
6313
            case TOOL_QUIZ:
6314
                if (empty($sessionId)) {
6315
                    $objExerciseTmp = new Exercise($courseId);
6316
                    $objExerciseTmp->read($item_id);
6317
                    if ('visible' === $visibility) {
6318
                        $objExerciseTmp->enable();
6319
                        $objExerciseTmp->save();
6320
                    } else {
6321
                        $objExerciseTmp->disable();
6322
                        $objExerciseTmp->save();
6323
                    }
6324
                }
6325
                break;
6326
        }
6327
    }
6328
}
6329
6330
function api_get_roles()
6331
{
6332
    $hierarchy = Container::$container->getParameter('security.role_hierarchy.roles');
6333
    $roles = [];
6334
    array_walk_recursive($hierarchy, function ($role) use (&$roles) {
6335
        $roles[$role] = $role;
6336
    });
6337
6338
    return $roles;
6339
}
6340
6341
function api_get_user_roles(): array
6342
{
6343
    $roles = [
6344
        'ROLE_TEACHER',
6345
        'ROLE_STUDENT',
6346
        'ROLE_RRHH',
6347
        'ROLE_SESSION_MANAGER',
6348
        'ROLE_STUDENT_BOSS',
6349
        'ROLE_INVITEE',
6350
        'ROLE_USER',
6351
    ];
6352
6353
    return array_combine($roles, $roles);
6354
}
6355
6356
/**
6357
 * @param string $file
6358
 *
6359
 * @return string
6360
 */
6361
function api_get_js_simple($file)
6362
{
6363
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
6364
}
6365
6366
/**
6367
 * Modify default memory_limit and max_execution_time limits
6368
 * Needed when processing long tasks.
6369
 */
6370
function api_set_more_memory_and_time_limits()
6371
{
6372
    if (function_exists('ini_set')) {
6373
        api_set_memory_limit('256M');
6374
        ini_set('max_execution_time', 1800);
6375
    }
6376
}
6377
6378
/**
6379
 * Tries to set memory limit, if authorized and new limit is higher than current.
6380
 *
6381
 * @param string $mem New memory limit
6382
 *
6383
 * @return bool True on success, false on failure or current is higher than suggested
6384
 * @assert (null) === false
6385
 * @assert (-1) === false
6386
 * @assert (0) === true
6387
 * @assert ('1G') === true
6388
 */
6389
function api_set_memory_limit($mem)
6390
{
6391
    //if ini_set() not available, this function is useless
6392
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
6393
        return false;
6394
    }
6395
6396
    $memory_limit = ini_get('memory_limit');
6397
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
6398
        ini_set('memory_limit', $mem);
6399
6400
        return true;
6401
    }
6402
6403
    return false;
6404
}
6405
6406
/**
6407
 * Gets memory limit in bytes.
6408
 *
6409
 * @param string The memory size (128M, 1G, 1000K, etc)
6410
 *
6411
 * @return int
6412
 * @assert (null) === false
6413
 * @assert ('1t')  === 1099511627776
6414
 * @assert ('1g')  === 1073741824
6415
 * @assert ('1m')  === 1048576
6416
 * @assert ('100k') === 102400
6417
 */
6418
function api_get_bytes_memory_limit($mem)
6419
{
6420
    $size = strtolower(substr($mem, -1));
6421
6422
    switch ($size) {
6423
        case 't':
6424
            $mem = (int) substr($mem, -1) * 1024 * 1024 * 1024 * 1024;
6425
            break;
6426
        case 'g':
6427
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024 * 1024;
6428
            break;
6429
        case 'm':
6430
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024;
6431
            break;
6432
        case 'k':
6433
            $mem = (int) substr($mem, 0, -1) * 1024;
6434
            break;
6435
        default:
6436
            // we assume it's integer only
6437
            $mem = (int) $mem;
6438
            break;
6439
    }
6440
6441
    return $mem;
6442
}
6443
6444
/**
6445
 * Finds all the information about a user from username instead of user id.
6446
 *
6447
 * @param string $officialCode
6448
 *
6449
 * @return array $user_info user_id, lastname, firstname, username, email, ...
6450
 *
6451
 * @author Yannick Warnier <[email protected]>
6452
 */
6453
function api_get_user_info_from_official_code($officialCode)
6454
{
6455
    if (empty($officialCode)) {
6456
        return false;
6457
    }
6458
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
6459
            WHERE official_code ='".Database::escape_string($officialCode)."'";
6460
    $result = Database::query($sql);
6461
    if (Database::num_rows($result) > 0) {
6462
        $result_array = Database::fetch_array($result);
6463
6464
        return _api_format_user($result_array);
6465
    }
6466
6467
    return false;
6468
}
6469
6470
/**
6471
 * @param string $usernameInputId
6472
 * @param string $passwordInputId
6473
 *
6474
 * @return string|null
6475
 */
6476
function api_get_password_checker_js($usernameInputId, $passwordInputId)
6477
{
6478
    $checkPass = api_get_setting('allow_strength_pass_checker');
6479
    $useStrengthPassChecker = 'true' === $checkPass;
6480
6481
    if (false === $useStrengthPassChecker) {
6482
        return null;
6483
    }
6484
6485
    $minRequirements = Security::getPasswordRequirements()['min'];
6486
6487
    $options = [
6488
        'rules' => [],
6489
    ];
6490
6491
    if ($minRequirements['length'] > 0) {
6492
        $options['rules'][] = [
6493
            'minChar' => $minRequirements['length'],
6494
            'pattern' => '.',
6495
            'helpText' => sprintf(
6496
                get_lang('Minimum %s characters in total'),
6497
                $minRequirements['length']
6498
            ),
6499
        ];
6500
    }
6501
6502
    if ($minRequirements['lowercase'] > 0) {
6503
        $options['rules'][] = [
6504
            'minChar' => $minRequirements['lowercase'],
6505
            'pattern' => '[a-z]',
6506
            'helpText' => sprintf(
6507
                get_lang('Minimum %s lowercase characters'),
6508
                $minRequirements['lowercase']
6509
            ),
6510
        ];
6511
    }
6512
6513
    if ($minRequirements['uppercase'] > 0) {
6514
        $options['rules'][] = [
6515
            'minChar' => $minRequirements['uppercase'],
6516
            'pattern' => '[A-Z]',
6517
            'helpText' => sprintf(
6518
                get_lang('Minimum %s uppercase characters'),
6519
                $minRequirements['uppercase']
6520
            ),
6521
        ];
6522
    }
6523
6524
    if ($minRequirements['numeric'] > 0) {
6525
        $options['rules'][] = [
6526
            'minChar' => $minRequirements['numeric'],
6527
            'pattern' => '[0-9]',
6528
            'helpText' => sprintf(
6529
                get_lang('Minimum %s numerical (0-9) characters'),
6530
                $minRequirements['numeric']
6531
            ),
6532
        ];
6533
    }
6534
6535
    if ($minRequirements['specials'] > 0) {
6536
        $options['rules'][] = [
6537
            'minChar' => $minRequirements['specials'],
6538
            'pattern' => '[!"#$%&\'()*+,\-./\\\:;<=>?@[\\]^_`{|}~]',
6539
            'helpText' => sprintf(
6540
                get_lang('Minimum %s special characters'),
6541
                $minRequirements['specials']
6542
            ),
6543
        ];
6544
    }
6545
6546
    $js = api_get_js('password-checker/password-checker.js');
6547
    $js .= "<script>
6548
    $(function() {
6549
        $('".$passwordInputId."').passwordChecker(".json_encode($options).");
6550
    });
6551
    </script>";
6552
6553
    return $js;
6554
}
6555
6556
/**
6557
 * create an user extra field called 'captcha_blocked_until_date'.
6558
 *
6559
 * @param string $username
6560
 *
6561
 * @return bool
6562
 */
6563
function api_block_account_captcha($username)
6564
{
6565
    $userInfo = api_get_user_info_from_username($username);
6566
    if (empty($userInfo)) {
6567
        return false;
6568
    }
6569
    $minutesToBlock = api_get_setting('captcha_time_to_block');
6570
    $time = time() + $minutesToBlock * 60;
6571
    UserManager::update_extra_field_value(
6572
        $userInfo['user_id'],
6573
        'captcha_blocked_until_date',
6574
        api_get_utc_datetime($time)
6575
    );
6576
6577
    return true;
6578
}
6579
6580
/**
6581
 * @param string $username
6582
 *
6583
 * @return bool
6584
 */
6585
function api_clean_account_captcha($username)
6586
{
6587
    $userInfo = api_get_user_info_from_username($username);
6588
    if (empty($userInfo)) {
6589
        return false;
6590
    }
6591
    Session::erase('loginFailedCount');
6592
    UserManager::update_extra_field_value(
6593
        $userInfo['user_id'],
6594
        'captcha_blocked_until_date',
6595
        null
6596
    );
6597
6598
    return true;
6599
}
6600
6601
/**
6602
 * @param string $username
6603
 *
6604
 * @return bool
6605
 */
6606
function api_get_user_blocked_by_captcha($username)
6607
{
6608
    $userInfo = api_get_user_info_from_username($username);
6609
    if (empty($userInfo)) {
6610
        return false;
6611
    }
6612
    $data = UserManager::get_extra_user_data_by_field(
6613
        $userInfo['user_id'],
6614
        'captcha_blocked_until_date'
6615
    );
6616
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
6617
        return $data['captcha_blocked_until_date'];
6618
    }
6619
6620
    return false;
6621
}
6622
6623
/**
6624
 * If true, the drh can access all content (courses, users) inside a session.
6625
 *
6626
 * @return bool
6627
 */
6628
function api_drh_can_access_all_session_content()
6629
{
6630
    return 'true' === api_get_setting('drh_can_access_all_session_content');
6631
}
6632
6633
/**
6634
 * Checks if user can login as another user.
6635
 *
6636
 * @param int $loginAsUserId the user id to log in
6637
 * @param int $userId        my user id
6638
 *
6639
 * @return bool
6640
 */
6641
function api_can_login_as($loginAsUserId, $userId = null)
6642
{
6643
    $loginAsUserId = (int) $loginAsUserId;
6644
6645
    if (empty($loginAsUserId)) {
6646
        return false;
6647
    }
6648
6649
    if (empty($userId)) {
6650
        $userId = api_get_user_id();
6651
    }
6652
6653
    if ($loginAsUserId == $userId) {
6654
        return false;
6655
    }
6656
6657
    // Check if the user to login is an admin
6658
    if (api_is_platform_admin_by_id($loginAsUserId)) {
6659
        // Only super admins can login to admin accounts
6660
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
6661
            return false;
6662
        }
6663
    }
6664
6665
    $userInfo = api_get_user_info($loginAsUserId);
6666
6667
    $isDrh = function () use ($loginAsUserId) {
6668
        if (api_is_drh()) {
6669
            if (api_drh_can_access_all_session_content()) {
6670
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
6671
                    'drh_all',
6672
                    api_get_user_id()
6673
                );
6674
                $userList = [];
6675
                if (is_array($users)) {
6676
                    foreach ($users as $user) {
6677
                        $userList[] = $user['id'];
6678
                    }
6679
                }
6680
                if (in_array($loginAsUserId, $userList)) {
6681
                    return true;
6682
                }
6683
            } else {
6684
                if (api_is_drh() &&
6685
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
6686
                ) {
6687
                    return true;
6688
                }
6689
            }
6690
        }
6691
6692
        return false;
6693
    };
6694
6695
    $loginAsStatusForSessionAdmins = [STUDENT];
6696
6697
    if ('true' === api_get_setting('session.allow_session_admin_login_as_teacher')) {
6698
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
6699
    }
6700
6701
    return api_is_platform_admin() ||
6702
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
6703
        $isDrh();
6704
}
6705
6706
/**
6707
 * Return true on https install.
6708
 *
6709
 * @return bool
6710
 */
6711
function api_is_https()
6712
{
6713
    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...
6714
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
6715
    ) {
6716
        $isSecured = true;
6717
    } else {
6718
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
6719
            $isSecured = true;
6720
        } else {
6721
            $isSecured = false;
6722
            // last chance
6723
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
6724
                $isSecured = true;
6725
            }
6726
        }
6727
    }
6728
6729
    return $isSecured;
6730
}
6731
6732
/**
6733
 * Return protocol (http or https).
6734
 *
6735
 * @return string
6736
 */
6737
function api_get_protocol()
6738
{
6739
    return api_is_https() ? 'https' : 'http';
6740
}
6741
6742
/**
6743
 * Get origin.
6744
 *
6745
 * @param string
6746
 *
6747
 * @return string
6748
 */
6749
function api_get_origin()
6750
{
6751
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
6752
}
6753
6754
/**
6755
 * Warns an user that the portal reach certain limit.
6756
 *
6757
 * @param string $limitName
6758
 */
6759
function api_warn_hosting_contact($limitName)
6760
{
6761
    $hostingParams = api_get_configuration_value(1);
6762
    $email = null;
6763
6764
    if (!empty($hostingParams)) {
6765
        if (isset($hostingParams['hosting_contact_mail'])) {
6766
            $email = $hostingParams['hosting_contact_mail'];
6767
        }
6768
    }
6769
6770
    if (!empty($email)) {
6771
        $subject = get_lang('Hosting warning reached');
6772
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
6773
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
6774
        if (isset($hostingParams[$limitName])) {
6775
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
6776
        }
6777
        api_mail_html(null, $email, $subject, $body);
6778
    }
6779
}
6780
6781
/**
6782
 * Gets value of a variable from config/configuration.php
6783
 * Variables that are not set in the configuration.php file but set elsewhere:
6784
 * - virtual_css_theme_folder (vchamilo plugin)
6785
 * - access_url (global.inc.php)
6786
 * - apc/apc_prefix (global.inc.php).
6787
 *
6788
 * @param string $variable
6789
 *
6790
 * @return bool|mixed
6791
 */
6792
function api_get_configuration_value($variable)
6793
{
6794
    global $_configuration;
6795
    // Check the current url id, id = 1 by default
6796
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
6797
6798
    $variable = trim($variable);
6799
6800
    // Check if variable exists
6801
    if (isset($_configuration[$variable])) {
6802
        if (is_array($_configuration[$variable])) {
6803
            // Check if it exists for the sub portal
6804
            if (array_key_exists($urlId, $_configuration[$variable])) {
6805
                return $_configuration[$variable][$urlId];
6806
            } else {
6807
                // Try to found element with id = 1 (master portal)
6808
                if (array_key_exists(1, $_configuration[$variable])) {
6809
                    return $_configuration[$variable][1];
6810
                }
6811
            }
6812
        }
6813
6814
        return $_configuration[$variable];
6815
    }
6816
6817
    return false;
6818
}
6819
6820
/**
6821
 * Retreives and returns a value in a hierarchical configuration array
6822
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
6823
 *
6824
 * @param string $path      the successive array keys, separated by the separator
6825
 * @param mixed  $default   value to be returned if not found, null by default
6826
 * @param string $separator '/' by default
6827
 * @param array  $array     the active configuration array by default
6828
 *
6829
 * @return mixed the found value or $default
6830
 */
6831
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
6832
{
6833
    $pos = strpos($path, $separator);
6834
    if (false === $pos) {
6835
        if (is_null($array)) {
6836
            return api_get_configuration_value($path);
6837
        }
6838
        if (is_array($array) && array_key_exists($path, $array)) {
6839
            return $array[$path];
6840
        }
6841
6842
        return $default;
6843
    }
6844
    $key = substr($path, 0, $pos);
6845
    if (is_null($array)) {
6846
        $newArray = api_get_configuration_value($key);
6847
    } elseif (is_array($array) && array_key_exists($key, $array)) {
6848
        $newArray = $array[$key];
6849
    } else {
6850
        return $default;
6851
    }
6852
    if (is_array($newArray)) {
6853
        $newPath = substr($path, $pos + 1);
6854
6855
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
6856
    }
6857
6858
    return $default;
6859
}
6860
6861
/**
6862
 * Retrieves and returns a value in a hierarchical configuration array
6863
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
6864
 *
6865
 * @param array  $array     the recursive array that contains the value to be returned (or not)
6866
 * @param string $path      the successive array keys, separated by the separator
6867
 * @param mixed  $default   the value to be returned if not found
6868
 * @param string $separator the separator substring
6869
 *
6870
 * @return mixed the found value or $default
6871
 */
6872
function api_array_sub_value($array, $path, $default = null, $separator = '/')
6873
{
6874
    $pos = strpos($path, $separator);
6875
    if (false === $pos) {
6876
        if (is_array($array) && array_key_exists($path, $array)) {
6877
            return $array[$path];
6878
        }
6879
6880
        return $default;
6881
    }
6882
    $key = substr($path, 0, $pos);
6883
    if (is_array($array) && array_key_exists($key, $array)) {
6884
        $newArray = $array[$key];
6885
    } else {
6886
        return $default;
6887
    }
6888
    if (is_array($newArray)) {
6889
        $newPath = substr($path, $pos + 1);
6890
6891
        return api_array_sub_value($newArray, $newPath, $default);
6892
    }
6893
6894
    return $default;
6895
}
6896
6897
/**
6898
 * Returns supported image extensions in the portal.
6899
 *
6900
 * @param bool $supportVectors Whether vector images should also be accepted or not
6901
 *
6902
 * @return array Supported image extensions in the portal
6903
 */
6904
function api_get_supported_image_extensions($supportVectors = true)
6905
{
6906
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
6907
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
6908
    if ($supportVectors) {
6909
        array_push($supportedImageExtensions, 'svg');
6910
    }
6911
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
6912
        array_push($supportedImageExtensions, 'webp');
6913
    }
6914
6915
    return $supportedImageExtensions;
6916
}
6917
6918
/**
6919
 * This setting changes the registration status for the campus.
6920
 *
6921
 * @author Patrick Cool <[email protected]>, Ghent University
6922
 *
6923
 * @version August 2006
6924
 *
6925
 * @param bool $listCampus Whether we authorize
6926
 *
6927
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
6928
 */
6929
function api_register_campus($listCampus = true)
6930
{
6931
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6932
6933
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
6934
    Database::query($sql);
6935
6936
    if (!$listCampus) {
6937
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
6938
        Database::query($sql);
6939
    }
6940
}
6941
6942
/**
6943
 * Check whether the user type should be exclude.
6944
 * Such as invited or anonymous users.
6945
 *
6946
 * @param bool $checkDB Optional. Whether check the user status
6947
 * @param int  $userId  Options. The user id
6948
 *
6949
 * @return bool
6950
 */
6951
function api_is_excluded_user_type($checkDB = false, $userId = 0)
6952
{
6953
    if ($checkDB) {
6954
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
6955
6956
        if (0 == $userId) {
6957
            return true;
6958
        }
6959
6960
        $userInfo = api_get_user_info($userId);
6961
6962
        switch ($userInfo['status']) {
6963
            case INVITEE:
6964
            case ANONYMOUS:
6965
                return true;
6966
            default:
6967
                return false;
6968
        }
6969
    }
6970
6971
    $isInvited = api_is_invitee();
6972
    $isAnonymous = api_is_anonymous();
6973
6974
    if ($isInvited || $isAnonymous) {
6975
        return true;
6976
    }
6977
6978
    return false;
6979
}
6980
6981
/**
6982
 * Get the user status to ignore in reports.
6983
 *
6984
 * @param string $format Optional. The result type (array or string)
6985
 *
6986
 * @return array|string
6987
 */
6988
function api_get_users_status_ignored_in_reports($format = 'array')
6989
{
6990
    $excludedTypes = [
6991
        INVITEE,
6992
        ANONYMOUS,
6993
    ];
6994
6995
    if ('string' == $format) {
6996
        return implode(', ', $excludedTypes);
6997
    }
6998
6999
    return $excludedTypes;
7000
}
7001
7002
/**
7003
 * Set the Site Use Cookie Warning for 1 year.
7004
 */
7005
function api_set_site_use_cookie_warning_cookie()
7006
{
7007
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
7008
}
7009
7010
/**
7011
 * Return true if the Site Use Cookie Warning Cookie warning exists.
7012
 *
7013
 * @return bool
7014
 */
7015
function api_site_use_cookie_warning_cookie_exist()
7016
{
7017
    return isset($_COOKIE['ChamiloUsesCookies']);
7018
}
7019
7020
/**
7021
 * Given a number of seconds, format the time to show hours, minutes and seconds.
7022
 *
7023
 * @param int    $time         The time in seconds
7024
 * @param string $originFormat Optional. PHP o JS
7025
 *
7026
 * @return string (00h00'00")
7027
 */
7028
function api_format_time($time, $originFormat = 'php')
7029
{
7030
    $h = get_lang('h');
7031
    $hours = $time / 3600;
7032
    $mins = ($time % 3600) / 60;
7033
    $secs = ($time % 60);
7034
7035
    if ($time < 0) {
7036
        $hours = 0;
7037
        $mins = 0;
7038
        $secs = 0;
7039
    }
7040
7041
    if ('js' === $originFormat) {
7042
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
7043
    } else {
7044
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
7045
    }
7046
7047
    return $formattedTime;
7048
}
7049
7050
function api_set_noreply_and_from_address_to_mailer(
7051
    TemplatedEmail $email,
7052
    array $sender,
7053
    array $replyToAddress = []
7054
): void {
7055
    $validator = Container::getLegacyHelper()->getValidator();
7056
    $emailConstraint = new Assert\Email();
7057
7058
    $noReplyAddress = api_get_setting('noreply_email_address');
7059
    $avoidReplyToAddress = false;
7060
7061
    if (!empty($noReplyAddress)) {
7062
        // $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
7063
    }
7064
7065
    // Default values
7066
    $notification = new Notification();
7067
    $defaultSenderName = $notification->getDefaultPlatformSenderName();
7068
    $defaultSenderEmail = $notification->getDefaultPlatformSenderEmail();
7069
7070
    // If the parameter is set don't use the admin.
7071
    $senderName = !empty($sender['name']) ? $sender['name'] : $defaultSenderName;
7072
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $defaultSenderEmail;
7073
7074
    // Send errors to the platform admin
7075
    $adminEmail = api_get_setting('admin.administrator_email');
7076
7077
    $adminEmailValidation = $validator->validate($adminEmail, $emailConstraint);
7078
7079
    if (!empty($adminEmail) && 0 === $adminEmailValidation->count()) {
7080
        $email
7081
            ->getHeaders()
7082
            ->addIdHeader('Errors-To', $adminEmail)
7083
        ;
7084
    }
7085
7086
    if (!$avoidReplyToAddress) {
7087
        $replyToEmailValidation = $validator->validate($replyToAddress['mail'], $emailConstraint);
7088
7089
        if (!empty($replyToAddress) && 0 === $replyToEmailValidation->count()) {
7090
            $email->addReplyTo(new Address($replyToAddress['mail'], $replyToAddress['name']));
7091
        }
7092
    }
7093
7094
    if ('true' === api_get_setting('mail.smtp_unique_sender')) {
7095
        $senderName = $defaultSenderName;
7096
        $senderEmail = $defaultSenderEmail;
7097
7098
        $email->sender(new Address($senderEmail, $senderName));
7099
    }
7100
7101
    if ($senderEmail) {
7102
        $email->from(new Address($senderEmail, $senderName));
7103
    }
7104
}
7105
7106
/**
7107
 * Sends an email
7108
 * Sender name and email can be specified, if not specified
7109
 * name and email of the platform admin are used.
7110
 *
7111
 * @param string    name of recipient
7112
 * @param string    email of recipient
7113
 * @param string    email subject
7114
 * @param string    email body
7115
 * @param string    sender name
7116
 * @param string    sender e-mail
7117
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
7118
 * @param array     data file (path and filename)
7119
 * @param bool      True for attaching a embedded file inside content html (optional)
7120
 * @param array     Additional parameters
7121
 *
7122
 * @return bool true if mail was sent
7123
 */
7124
function api_mail_html(
7125
    $recipientName,
7126
    $recipientEmail,
7127
    $subject,
7128
    $body,
7129
    $senderName = '',
7130
    $senderEmail = '',
7131
    $extra_headers = [],
7132
    $data_file = [],
7133
    $embeddedImage = false,
7134
    $additionalParameters = [],
7135
    string $sendErrorTo = null
7136
) {
7137
    $mailHelper = Container::$container->get(MailHelper::class);
7138
7139
    return $mailHelper->send(
7140
        $recipientName,
7141
        $recipientEmail,
7142
        $subject,
7143
        $body,
7144
        $senderName,
7145
        $senderEmail,
7146
        $extra_headers,
7147
        $data_file,
7148
        $embeddedImage,
7149
        $additionalParameters,
7150
        $sendErrorTo
7151
    );
7152
}
7153
7154
/**
7155
 * @param int  $tool       Possible values: GroupManager::GROUP_TOOL_*
7156
 * @param bool $showHeader
7157
 */
7158
function api_protect_course_group($tool, $showHeader = true)
7159
{
7160
    $groupId = api_get_group_id();
7161
    if (!empty($groupId)) {
7162
        if (api_is_platform_admin()) {
7163
            return true;
7164
        }
7165
7166
        if (api_is_allowed_to_edit(false, true, true)) {
7167
            return true;
7168
        }
7169
7170
        $userId = api_get_user_id();
7171
        $sessionId = api_get_session_id();
7172
        if (!empty($sessionId)) {
7173
            if (api_is_coach($sessionId, api_get_course_int_id())) {
7174
                return true;
7175
            }
7176
7177
            if (api_is_drh()) {
7178
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
7179
                    return true;
7180
                }
7181
            }
7182
        }
7183
7184
        $group = api_get_group_entity($groupId);
7185
7186
        // Group doesn't exists
7187
        if (null === $group) {
7188
            api_not_allowed($showHeader);
7189
        }
7190
7191
        // Check group access
7192
        $allow = GroupManager::userHasAccess(
7193
            $userId,
7194
            $group,
7195
            $tool
7196
        );
7197
7198
        if (!$allow) {
7199
            api_not_allowed($showHeader);
7200
        }
7201
    }
7202
7203
    return false;
7204
}
7205
7206
/**
7207
 * Check if a date is in a date range.
7208
 *
7209
 * @param datetime $startDate
7210
 * @param datetime $endDate
7211
 * @param datetime $currentDate
7212
 *
7213
 * @return bool true if date is in rage, false otherwise
7214
 */
7215
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
7216
{
7217
    $startDate = strtotime(api_get_local_time($startDate));
7218
    $endDate = strtotime(api_get_local_time($endDate));
7219
    $currentDate = strtotime(api_get_local_time($currentDate));
7220
7221
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
7222
        return true;
7223
    }
7224
7225
    return false;
7226
}
7227
7228
/**
7229
 * Eliminate the duplicates of a multidimensional array by sending the key.
7230
 *
7231
 * @param array $array multidimensional array
7232
 * @param int   $key   key to find to compare
7233
 *
7234
 * @return array
7235
 */
7236
function api_unique_multidim_array($array, $key)
7237
{
7238
    $temp_array = [];
7239
    $i = 0;
7240
    $key_array = [];
7241
7242
    foreach ($array as $val) {
7243
        if (!in_array($val[$key], $key_array)) {
7244
            $key_array[$i] = $val[$key];
7245
            $temp_array[$i] = $val;
7246
        }
7247
        $i++;
7248
    }
7249
7250
    return $temp_array;
7251
}
7252
7253
/**
7254
 * Limit the access to Session Admins when the limit_session_admin_role
7255
 * configuration variable is set to true.
7256
 */
7257
function api_protect_limit_for_session_admin()
7258
{
7259
    $limitAdmin = api_get_setting('limit_session_admin_role');
7260
    if (api_is_session_admin() && 'true' === $limitAdmin) {
7261
        api_not_allowed(true);
7262
    }
7263
}
7264
7265
/**
7266
 * Limits that a session admin has access to list users.
7267
 * When limit_session_admin_list_users configuration variable is set to true.
7268
 */
7269
function api_protect_session_admin_list_users()
7270
{
7271
    $limitAdmin = ('true' === api_get_setting('session.limit_session_admin_list_users'));
7272
7273
    if (api_is_session_admin() && true === $limitAdmin) {
7274
        api_not_allowed(true);
7275
    }
7276
}
7277
7278
/**
7279
 * @return bool
7280
 */
7281
function api_is_student_view_active(): bool
7282
{
7283
    $studentView = Session::read('studentview');
7284
7285
    return 'studentview' === $studentView;
7286
}
7287
7288
/**
7289
 * Converts string value to float value.
7290
 *
7291
 * 3.141516 => 3.141516
7292
 * 3,141516 => 3.141516
7293
 *
7294
 * @todo WIP
7295
 *
7296
 * @param string $number
7297
 *
7298
 * @return float
7299
 */
7300
function api_float_val($number)
7301
{
7302
    return (float) str_replace(',', '.', trim($number));
7303
}
7304
7305
/**
7306
 * Converts float values
7307
 * Example if $decimals = 2.
7308
 *
7309
 * 3.141516 => 3.14
7310
 * 3,141516 => 3,14
7311
 *
7312
 * @param string $number            number in iso code
7313
 * @param int    $decimals
7314
 * @param string $decimalSeparator
7315
 * @param string $thousandSeparator
7316
 *
7317
 * @return bool|string
7318
 */
7319
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
7320
{
7321
    $number = api_float_val($number);
7322
7323
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
7324
}
7325
7326
/**
7327
 * Set location url with a exit break by default.
7328
 *
7329
 * @param string $url
7330
 * @param bool   $exit
7331
 */
7332
function api_location($url, $exit = true)
7333
{
7334
    header('Location: '.$url);
7335
7336
    if ($exit) {
7337
        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...
7338
    }
7339
}
7340
7341
/**
7342
 * @param string $from
7343
 * @param string $to
7344
 *
7345
 * @return string
7346
 */
7347
function api_get_relative_path($from, $to)
7348
{
7349
    // some compatibility fixes for Windows paths
7350
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
7351
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
7352
    $from = str_replace('\\', '/', $from);
7353
    $to = str_replace('\\', '/', $to);
7354
7355
    $from = explode('/', $from);
7356
    $to = explode('/', $to);
7357
    $relPath = $to;
7358
7359
    foreach ($from as $depth => $dir) {
7360
        // find first non-matching dir
7361
        if ($dir === $to[$depth]) {
7362
            // ignore this directory
7363
            array_shift($relPath);
7364
        } else {
7365
            // get number of remaining dirs to $from
7366
            $remaining = count($from) - $depth;
7367
            if ($remaining > 1) {
7368
                // add traversals up to first matching dir
7369
                $padLength = (count($relPath) + $remaining - 1) * -1;
7370
                $relPath = array_pad($relPath, $padLength, '..');
7371
                break;
7372
            } else {
7373
                $relPath[0] = './'.$relPath[0];
7374
            }
7375
        }
7376
    }
7377
7378
    return implode('/', $relPath);
7379
}
7380
7381
/**
7382
 * @param string $template
7383
 *
7384
 * @return string
7385
 */
7386
function api_find_template($template)
7387
{
7388
    return Template::findTemplateFilePath($template);
7389
}
7390
7391
/**
7392
 * @return array
7393
 */
7394
function api_get_language_list_for_flag()
7395
{
7396
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
7397
    $sql = "SELECT english_name, isocode FROM $table
7398
            ORDER BY original_name ASC";
7399
    static $languages = [];
7400
    if (empty($languages)) {
7401
        $result = Database::query($sql);
7402
        while ($row = Database::fetch_array($result)) {
7403
            $languages[$row['english_name']] = $row['isocode'];
7404
        }
7405
        $languages['english'] = 'gb';
7406
    }
7407
7408
    return $languages;
7409
}
7410
7411
function api_create_zip(string $name): ZipStream
7412
{
7413
    $zipStreamOptions = new Archive();
7414
    $zipStreamOptions->setSendHttpHeaders(true);
7415
    $zipStreamOptions->setContentDisposition('attachment');
7416
    $zipStreamOptions->setContentType('application/x-zip');
7417
7418
    return new ZipStream($name, $zipStreamOptions);
7419
}
7420
7421
function api_get_language_translate_html(): string
7422
{
7423
    $translate = 'true' === api_get_setting('editor.translate_html');
7424
7425
    if (!$translate) {
7426
        return '';
7427
    }
7428
7429
    /*$languageList = api_get_languages();
7430
    $hideAll = '';
7431
    foreach ($languageList as $isocode => $name) {
7432
        $hideAll .= '
7433
        $(".mce-translatehtml").hide();
7434
        $("span:lang('.$isocode.')").filter(
7435
            function(e, val) {
7436
                // Only find the spans if they have set the lang
7437
                if ($(this).attr("lang") == null) {
7438
                    return false;
7439
                }
7440
                // Ignore ckeditor classes
7441
                return !this.className.match(/cke(.*)/);
7442
        }).hide();'."\n";
7443
    }*/
7444
7445
    $userInfo = api_get_user_info();
7446
    if (!empty($userInfo['language'])) {
7447
        $isoCode = $userInfo['language'];
7448
7449
        return '
7450
            $(function() {
7451
                $(".mce-translatehtml").hide();
7452
                var defaultLanguageFromUser = "'.$isoCode.'";
7453
                $("span:lang('.$isoCode.')").show();
7454
            });
7455
        ';
7456
    }
7457
7458
    return '';
7459
}
7460
7461
function api_protect_webservices()
7462
{
7463
    if (api_get_configuration_value('disable_webservices')) {
7464
        echo "Webservices are disabled. \n";
7465
        echo "To enable, add \$_configuration['disable_webservices'] = true; in configuration.php";
7466
        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...
7467
    }
7468
}
7469