Passed
Pull Request — master (#5462)
by Angel Fernando Quiroz
11:48 queued 04:29
created

api_mail_html()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 13
c 1
b 0
f 0
nc 1
nop 11
dl 0
loc 27
rs 9.8333

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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

2077
        $url .= '&origin='./** @scrutinizer ignore-type */ $origin;
Loading history...
2078
    }
2079
2080
    return $url;
2081
}
2082
2083
/**
2084
 * Get if we visited a gradebook page.
2085
 *
2086
 * @return bool
2087
 */
2088
function api_is_in_gradebook()
2089
{
2090
    return Session::read('in_gradebook', false);
2091
}
2092
2093
/**
2094
 * Set that we are in a page inside a gradebook.
2095
 */
2096
function api_set_in_gradebook()
2097
{
2098
    Session::write('in_gradebook', true);
2099
}
2100
2101
/**
2102
 * Remove gradebook session.
2103
 */
2104
function api_remove_in_gradebook()
2105
{
2106
    Session::erase('in_gradebook');
2107
}
2108
2109
/**
2110
 * Returns the current course info array see api_format_course_array()
2111
 * If the course_code is given, the returned array gives info about that
2112
 * particular course, if none given it gets the course info from the session.
2113
 *
2114
 * @param string $courseCode
2115
 *
2116
 * @return array
2117
 */
2118
function api_get_course_info($courseCode = null)
2119
{
2120
    if (!empty($courseCode)) {
2121
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2122
2123
        return api_format_course_array($course);
2124
    }
2125
2126
    $course = Session::read('_course');
2127
    if ('-1' == $course) {
2128
        $course = [];
2129
    }
2130
2131
    if (empty($course) && isset($_REQUEST['cid'])) {
2132
        $course = api_get_course_info_by_id((int) $_REQUEST['cid']);
2133
    }
2134
2135
    return $course;
2136
}
2137
2138
/**
2139
 * @param int $courseId
2140
 */
2141
function api_get_course_entity($courseId = 0): ?Course
2142
{
2143
    if (empty($courseId)) {
2144
        $courseId = api_get_course_int_id();
2145
    }
2146
2147
    if (empty($courseId)) {
2148
        return null;
2149
    }
2150
2151
    return Container::getCourseRepository()->find($courseId);
2152
}
2153
2154
/**
2155
 * @param int $id
2156
 */
2157
function api_get_session_entity($id = 0): ?SessionEntity
2158
{
2159
    if (empty($id)) {
2160
        $id = api_get_session_id();
2161
    }
2162
2163
    if (empty($id)) {
2164
        return null;
2165
    }
2166
2167
    return Container::getSessionRepository()->find($id);
2168
}
2169
2170
/**
2171
 * @param int $id
2172
 */
2173
function api_get_group_entity($id = 0): ?CGroup
2174
{
2175
    if (empty($id)) {
2176
        $id = api_get_group_id();
2177
    }
2178
2179
    return Container::getGroupRepository()->find($id);
2180
}
2181
2182
/**
2183
 * @param int $id
2184
 */
2185
function api_get_url_entity($id = 0): ?AccessUrl
2186
{
2187
    if (empty($id)) {
2188
        $id = api_get_current_access_url_id();
2189
    }
2190
2191
    return Container::getAccessUrlRepository()->find($id);
2192
}
2193
2194
/**
2195
 * Returns the current course info array.
2196
2197
 * Now if the course_code is given, the returned array gives info about that
2198
 * particular course, not specially the current one.
2199
 *
2200
 * @param int $id Numeric ID of the course
2201
 *
2202
 * @return array The course info as an array formatted by api_format_course_array, including category.title
2203
 */
2204
function api_get_course_info_by_id(?int $id = 0)
2205
{
2206
    if (empty($id)) {
2207
        $course = Session::read('_course', []);
2208
2209
        return $course;
2210
    }
2211
2212
    $course = Container::getCourseRepository()->find($id);
2213
    if (empty($course)) {
2214
        return [];
2215
    }
2216
2217
    return api_format_course_array($course);
2218
}
2219
2220
/**
2221
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2222
 * to switch from 'code' to 'id' in the array.
2223
 *
2224
 * @return array
2225
 *
2226
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2227
 */
2228
function api_format_course_array(Course $course = null)
2229
{
2230
    if (empty($course)) {
2231
        return [];
2232
    }
2233
2234
    $courseData = [];
2235
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2236
2237
    // Added
2238
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2239
    $courseData['name'] = $courseData['title'] = $course->getTitle(); // 'name' only used for backwards compatibility - should be removed in the long run
2240
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2241
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2242
    $courseData['titular'] = $course->getTutorName();
2243
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2244
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2245
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2246
2247
    $courseData['visibility'] = $course->getVisibility();
2248
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2249
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2250
    $courseData['activate_legal'] = $course->getActivateLegal();
2251
    $courseData['legal'] = $course->getLegal();
2252
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2253
    $courseData['video_url'] = $course->getVideoUrl();
2254
    $courseData['sticky'] = (int) $course->isSticky();
2255
2256
    $coursePath = '/course/';
2257
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2258
2259
    // Course password
2260
    $courseData['registration_code'] = $course->getRegistrationCode();
2261
    $courseData['disk_quota'] = $course->getDiskQuota();
2262
    $courseData['course_public_url'] = $webCourseHome;
2263
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2264
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2265
2266
    $image = Display::getMdiIcon(
2267
        ObjectIcon::COURSE,
2268
        'ch-tool-icon',
2269
        null,
2270
        ICON_SIZE_BIG
2271
    );
2272
2273
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2274
    if (!empty($illustration)) {
2275
        $image = $illustration;
2276
    }
2277
2278
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2279
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2280
2281
    return $courseData;
2282
}
2283
2284
/**
2285
 * Returns a difficult to guess password.
2286
 */
2287
function api_generate_password(int $length = 8, $useRequirements = true): string
2288
{
2289
    if ($length < 2) {
2290
        $length = 2;
2291
    }
2292
2293
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2294
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2295
    $minNumbers = 2;
2296
    $length = $length - $minNumbers;
2297
    $minLowerCase = round($length / 2);
2298
    $minUpperCase = $length - $minLowerCase;
2299
2300
    $password = '';
2301
    $passwordRequirements = $useRequirements ? Security::getPasswordRequirements() : [];
2302
2303
    $factory = new RandomLib\Factory();
2304
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2305
2306
    if (!empty($passwordRequirements)) {
2307
        $length = $passwordRequirements['min']['length'];
2308
        $minNumbers = $passwordRequirements['min']['numeric'];
2309
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2310
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2311
2312
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2313
        // Add the rest to fill the length requirement
2314
        if ($rest > 0) {
2315
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2316
        }
2317
    }
2318
2319
    // Min digits default 2
2320
    for ($i = 0; $i < $minNumbers; $i++) {
2321
        $password .= $generator->generateInt(2, 9);
2322
    }
2323
2324
    // Min lowercase
2325
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2326
2327
    // Min uppercase
2328
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2329
    $password = str_shuffle($password);
2330
2331
    return $password;
2332
}
2333
2334
/**
2335
 * Checks a password to see wether it is OK to use.
2336
 *
2337
 * @param string $password
2338
 *
2339
 * @return bool if the password is acceptable, false otherwise
2340
 *              Notes about what a password "OK to use" is:
2341
 *              1. The password should be at least 5 characters long.
2342
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2343
 *              3. The password should contain at least 3 letters.
2344
 *              4. It should contain at least 2 digits.
2345
 *              Settings will change if the configuration value is set: password_requirements
2346
 */
2347
function api_check_password($password)
2348
{
2349
    $passwordRequirements = Security::getPasswordRequirements();
2350
2351
    $minLength = $passwordRequirements['min']['length'];
2352
    $minNumbers = $passwordRequirements['min']['numeric'];
2353
    // Optional
2354
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2355
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2356
2357
    $minLetters = $minLowerCase + $minUpperCase;
2358
    $passwordLength = api_strlen($password);
2359
2360
    $conditions = [
2361
        'min_length' => $passwordLength >= $minLength,
2362
    ];
2363
2364
    $digits = 0;
2365
    $lowerCase = 0;
2366
    $upperCase = 0;
2367
2368
    for ($i = 0; $i < $passwordLength; $i++) {
2369
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2370
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2371
            $upperCase++;
2372
        }
2373
2374
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2375
            $lowerCase++;
2376
        }
2377
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2378
            $digits++;
2379
        }
2380
    }
2381
2382
    // Min number of digits
2383
    $conditions['min_numeric'] = $digits >= $minNumbers;
2384
2385
    if (!empty($minUpperCase)) {
2386
        // Uppercase
2387
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2388
    }
2389
2390
    if (!empty($minLowerCase)) {
2391
        // Lowercase
2392
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2393
    }
2394
2395
    // Min letters
2396
    $letters = $upperCase + $lowerCase;
2397
    $conditions['min_letters'] = $letters >= $minLetters;
2398
2399
    $isPasswordOk = true;
2400
    foreach ($conditions as $condition) {
2401
        if (false === $condition) {
2402
            $isPasswordOk = false;
2403
            break;
2404
        }
2405
    }
2406
2407
    if (false === $isPasswordOk) {
2408
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2409
        $output .= Security::getPasswordRequirementsToString($conditions);
2410
2411
        Display::addFlash(Display::return_message($output, 'warning', false));
2412
    }
2413
2414
    return $isPasswordOk;
2415
}
2416
2417
/**
2418
 * Gets the current Chamilo (not PHP/cookie) session ID.
2419
 *
2420
 * @return int O if no active session, the session ID otherwise
2421
 */
2422
function api_get_session_id()
2423
{
2424
    return (int) Session::read('sid', 0);
2425
}
2426
2427
/**
2428
 * Gets the current Chamilo (not social network) group ID.
2429
 *
2430
 * @return int O if no active session, the session ID otherwise
2431
 */
2432
function api_get_group_id()
2433
{
2434
    return Session::read('gid', 0);
2435
}
2436
2437
/**
2438
 * Gets the current or given session name.
2439
 *
2440
 * @param   int     Session ID (optional)
2441
 *
2442
 * @return string The session name, or null if not found
2443
 */
2444
function api_get_session_name($session_id = 0)
2445
{
2446
    if (empty($session_id)) {
2447
        $session_id = api_get_session_id();
2448
        if (empty($session_id)) {
2449
            return null;
2450
        }
2451
    }
2452
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2453
    $s = "SELECT title FROM $t WHERE id = ".(int) $session_id;
2454
    $r = Database::query($s);
2455
    $c = Database::num_rows($r);
2456
    if ($c > 0) {
2457
        //technically, there can be only one, but anyway we take the first
2458
        $rec = Database::fetch_array($r);
2459
2460
        return $rec['title'];
2461
    }
2462
2463
    return null;
2464
}
2465
2466
/**
2467
 * Gets the session info by id.
2468
 *
2469
 * @param int $id Session ID
2470
 *
2471
 * @return array information of the session
2472
 */
2473
function api_get_session_info($id)
2474
{
2475
    return SessionManager::fetch($id);
2476
}
2477
2478
/**
2479
 * Gets the session visibility by session id.
2480
 *
2481
 * @param int  $session_id
2482
 * @param int  $courseId
2483
 * @param bool $ignore_visibility_for_admins
2484
 *
2485
 * @return int
2486
 *             0 = session still available,
2487
 *             SESSION_VISIBLE_READ_ONLY = 1,
2488
 *             SESSION_VISIBLE = 2,
2489
 *             SESSION_INVISIBLE = 3
2490
 */
2491
function api_get_session_visibility(
2492
    $session_id,
2493
    $courseId = null,
2494
    $ignore_visibility_for_admins = true,
2495
    $userId = 0
2496
) {
2497
    if (api_is_platform_admin()) {
2498
        if ($ignore_visibility_for_admins) {
2499
            return SESSION_AVAILABLE;
2500
        }
2501
    }
2502
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2503
2504
    $now = time();
2505
    if (empty($session_id)) {
2506
        return 0; // Means that the session is still available.
2507
    }
2508
2509
    $session_id = (int) $session_id;
2510
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2511
2512
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2513
2514
    if (Database::num_rows($result) <= 0) {
2515
        return SESSION_INVISIBLE;
2516
    }
2517
2518
    $row = Database::fetch_assoc($result);
2519
    $visibility = $row['visibility'];
2520
2521
    // I don't care the session visibility.
2522
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2523
        // Session duration per student.
2524
        if (isset($row['duration']) && !empty($row['duration'])) {
2525
            $duration = $row['duration'] * 24 * 60 * 60;
2526
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2527
2528
            // If there is a session duration but there is no previous
2529
            // access by the user, then the session is still available
2530
            if (0 == count($courseAccess)) {
2531
                return SESSION_AVAILABLE;
2532
            }
2533
2534
            $currentTime = time();
2535
            $firstAccess = isset($courseAccess['login_course_date'])
2536
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2537
                : 0;
2538
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2539
            $userDuration = isset($userDurationData['duration'])
2540
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2541
                : 0;
2542
2543
            $totalDuration = $firstAccess + $duration + $userDuration;
2544
2545
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2546
        }
2547
2548
        return SESSION_AVAILABLE;
2549
    }
2550
2551
    // If start date was set.
2552
    if (!empty($row['access_start_date'])) {
2553
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2554
    }
2555
2556
    // If the end date was set.
2557
    if (!empty($row['access_end_date'])) {
2558
        // Only if date_start said that it was ok
2559
        if (SESSION_AVAILABLE === $visibility) {
2560
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2561
                ? SESSION_AVAILABLE // Date still available
2562
                : $row['visibility']; // Session ends
2563
        }
2564
    }
2565
2566
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2567
    $isCoach = api_is_coach($session_id, $courseId);
2568
2569
    if ($isCoach) {
2570
        // Test start date.
2571
        if (!empty($row['coach_access_start_date'])) {
2572
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2573
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2574
        }
2575
2576
        // Test end date.
2577
        if (!empty($row['coach_access_end_date'])) {
2578
            if (SESSION_AVAILABLE === $visibility) {
2579
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2580
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2581
            }
2582
        }
2583
    }
2584
2585
    return $visibility;
2586
}
2587
2588
/**
2589
 * This function returns a (star) session icon if the session is not null and
2590
 * the user is not a student.
2591
 *
2592
 * @param int $sessionId
2593
 * @param int $statusId  User status id - if 5 (student), will return empty
2594
 *
2595
 * @return string Session icon
2596
 */
2597
function api_get_session_image($sessionId, User $user)
2598
{
2599
    $sessionId = (int) $sessionId;
2600
    $image = '';
2601
    if (!$user->hasRole('ROLE_STUDENT')) {
2602
        // Check whether is not a student
2603
        if ($sessionId > 0) {
2604
            $image = '&nbsp;&nbsp;'.Display::getMdiIcon(
2605
                ObjectIcon::STAR,
2606
                'ch-tool-icon',
2607
                'align:absmiddle;',
2608
                ICON_SIZE_SMALL,
2609
                get_lang('Session-specific resource')
2610
            );
2611
        }
2612
    }
2613
2614
    return $image;
2615
}
2616
2617
/**
2618
 * This function add an additional condition according to the session of the course.
2619
 *
2620
 * @param int    $session_id        session id
2621
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2622
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2623
 *                                  false for strict session condition
2624
 * @param string $session_field
2625
 *
2626
 * @return string condition of the session
2627
 */
2628
function api_get_session_condition(
2629
    $session_id,
2630
    $and = true,
2631
    $with_base_content = false,
2632
    $session_field = 'session_id'
2633
) {
2634
    $session_id = (int) $session_id;
2635
2636
    if (empty($session_field)) {
2637
        $session_field = 'session_id';
2638
    }
2639
    // Condition to show resources by session
2640
    $condition_add = $and ? ' AND ' : ' WHERE ';
2641
2642
    if ($with_base_content) {
2643
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2644
    } else {
2645
        if (empty($session_id)) {
2646
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2647
        } else {
2648
            $condition_session = $condition_add." $session_field = $session_id ";
2649
        }
2650
    }
2651
2652
    return $condition_session;
2653
}
2654
2655
/**
2656
 * Returns the value of a setting from the web-adjustable admin config settings.
2657
 *
2658
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2659
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2660
 * instead of
2661
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2662
 *
2663
 * @param string $variable The variable name
2664
 *
2665
 * @return string|array
2666
 */
2667
function api_get_setting($variable, $isArray = false, $key = null)
2668
{
2669
    $settingsManager = Container::getSettingsManager();
2670
    if (empty($settingsManager)) {
2671
        return '';
2672
    }
2673
    $variable = trim($variable);
2674
2675
    switch ($variable) {
2676
        case 'server_type':
2677
            $test = ['dev', 'test'];
2678
            $environment = Container::getEnvironment();
2679
            if (in_array($environment, $test)) {
2680
                return 'test';
2681
            }
2682
2683
            return 'prod';
2684
        case 'stylesheets':
2685
            $variable = 'platform.theme';
2686
        // deprecated settings
2687
        // no break
2688
        case 'openid_authentication':
2689
        case 'service_ppt2lp':
2690
        case 'formLogin_hide_unhide_label':
2691
            return false;
2692
            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...
2693
        case 'tool_visible_by_default_at_creation':
2694
            $values = $settingsManager->getSetting($variable);
2695
            $newResult = [];
2696
            foreach ($values as $parameter) {
2697
                $newResult[$parameter] = 'true';
2698
            }
2699
2700
            return $newResult;
2701
            break;
2702
        default:
2703
            $settingValue = $settingsManager->getSetting($variable, true);
2704
            if (is_string($settingValue) && $isArray && !empty($settingValue)) {
2705
                // Check if the value is a valid JSON string
2706
                $decodedValue = json_decode($settingValue, true);
2707
2708
                // If it's a valid JSON string and the result is an array, return it
2709
                if (is_array($decodedValue)) {
2710
                    return $decodedValue;
2711
                }
2712
2713
                // If it's not an array, continue with the normal flow
2714
                // Optional: If you need to evaluate the value using eval
2715
                $strArrayValue = rtrim($settingValue, ';');
2716
                $value = eval("return $strArrayValue;");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
2717
                if (is_array($value)) {
2718
                    return $value;
2719
                }
2720
            }
2721
2722
            // If the value is not a JSON array or wasn't returned previously, continue with the normal flow
2723
            if (!empty($key) && isset($settingValue[$variable][$key])) {
2724
                return $settingValue[$variable][$key];
2725
            }
2726
2727
            return $settingValue;
2728
            break;
2729
    }
2730
}
2731
2732
/**
2733
 * @param string $variable
2734
 * @param string $option
2735
 *
2736
 * @return bool
2737
 */
2738
function api_get_setting_in_list($variable, $option)
2739
{
2740
    $value = api_get_setting($variable);
2741
2742
    return in_array($option, $value);
2743
}
2744
2745
/**
2746
 * @param string $plugin
2747
 * @param string $variable
2748
 *
2749
 * @return string
2750
 */
2751
function api_get_plugin_setting($plugin, $variable)
2752
{
2753
    $variableName = $plugin.'_'.$variable;
2754
    //$result = api_get_setting($variableName);
2755
    $params = [
2756
        'category = ? AND subkey = ? AND variable = ?' => [
2757
            'Plugins',
2758
            $plugin,
2759
            $variableName,
2760
        ],
2761
    ];
2762
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2763
    $result = Database::select(
2764
        'selected_value',
2765
        $table,
2766
        ['where' => $params],
2767
        'one'
2768
    );
2769
    if ($result) {
2770
        $value = $result['selected_value'];
2771
        $serializedValue = @unserialize($result['selected_value'], []);
2772
        if (false !== $serializedValue) {
2773
            $value = $serializedValue;
2774
        }
2775
2776
        return $value;
2777
    }
2778
2779
    return null;
2780
    /// Old code
2781
2782
    $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...
2783
    $result = api_get_setting($variableName);
2784
2785
    if (isset($result[$plugin])) {
2786
        $value = $result[$plugin];
2787
2788
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2789
2790
        if (false !== $unserialized) {
2791
            $value = $unserialized;
2792
        }
2793
2794
        return $value;
2795
    }
2796
2797
    return null;
2798
}
2799
2800
/**
2801
 * Returns the value of a setting from the web-adjustable admin config settings.
2802
 */
2803
function api_get_settings_params($params)
2804
{
2805
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2806
2807
    return Database::select('*', $table, ['where' => $params]);
2808
}
2809
2810
/**
2811
 * @param array $params example: [id = ? => '1']
2812
 *
2813
 * @return array
2814
 */
2815
function api_get_settings_params_simple($params)
2816
{
2817
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2818
2819
    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...
2820
}
2821
2822
/**
2823
 * Returns the value of a setting from the web-adjustable admin config settings.
2824
 */
2825
function api_delete_settings_params($params)
2826
{
2827
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2828
2829
    return Database::delete($table, $params);
2830
}
2831
2832
/**
2833
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2834
 *
2835
 * @return string Escaped version of $_SERVER['PHP_SELF']
2836
 */
2837
function api_get_self()
2838
{
2839
    return htmlentities($_SERVER['PHP_SELF']);
2840
}
2841
2842
/**
2843
 * Checks whether current user is a platform administrator.
2844
 *
2845
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2846
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2847
 *
2848
 * @return bool true if the user has platform admin rights,
2849
 *              false otherwise
2850
 *
2851
 * @see usermanager::is_admin(user_id) for a user-id specific function
2852
 */
2853
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2854
{
2855
    $currentUser = api_get_current_user();
2856
2857
    if (null === $currentUser) {
2858
        return false;
2859
    }
2860
2861
    $isAdmin = $currentUser->hasRole('ROLE_ADMIN') || $currentUser->hasRole('ROLE_SUPER_ADMIN');
2862
2863
    if ($isAdmin) {
2864
        return true;
2865
    }
2866
2867
    if ($allowSessionAdmins && $currentUser->hasRole('ROLE_SESSION_MANAGER')) {
2868
        return true;
2869
    }
2870
2871
    if ($allowDrh && $currentUser->hasRole('ROLE_RRHH')) {
2872
        return true;
2873
    }
2874
2875
    return false;
2876
}
2877
2878
/**
2879
 * Checks whether the user given as user id is in the admin table.
2880
 *
2881
 * @param int $user_id If none provided, will use current user
2882
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2883
 *
2884
 * @return bool True if the user is admin, false otherwise
2885
 */
2886
function api_is_platform_admin_by_id($user_id = null, $url = null)
2887
{
2888
    $user_id = (int) $user_id;
2889
    if (empty($user_id)) {
2890
        $user_id = api_get_user_id();
2891
    }
2892
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2893
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2894
    $res = Database::query($sql);
2895
    $is_admin = 1 === Database::num_rows($res);
2896
    if (!$is_admin || !isset($url)) {
2897
        return $is_admin;
2898
    }
2899
    // We get here only if $url is set
2900
    $url = (int) $url;
2901
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2902
    $sql = "SELECT * FROM $url_user_table
2903
            WHERE access_url_id = $url AND user_id = $user_id";
2904
    $res = Database::query($sql);
2905
2906
    return 1 === Database::num_rows($res);
2907
}
2908
2909
/**
2910
 * Checks whether current user is allowed to create courses.
2911
 *
2912
 * @return bool true if the user has course creation rights,
2913
 *              false otherwise
2914
 */
2915
function api_is_allowed_to_create_course()
2916
{
2917
    if (api_is_platform_admin()) {
2918
        return true;
2919
    }
2920
2921
    // Teachers can only create courses
2922
    if (api_is_teacher()) {
2923
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
2924
            return true;
2925
        } else {
2926
            return false;
2927
        }
2928
    }
2929
2930
    return Session::read('is_allowedCreateCourse');
2931
}
2932
2933
/**
2934
 * Checks whether the current user is a course administrator.
2935
 *
2936
 * @return bool True if current user is a course administrator
2937
 */
2938
function api_is_course_admin()
2939
{
2940
    if (api_is_platform_admin()) {
2941
        return true;
2942
    }
2943
2944
    $user = api_get_current_user();
2945
    if ($user) {
2946
        if (
2947
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
2948
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
2949
        ) {
2950
            return true;
2951
        }
2952
    }
2953
2954
    return false;
2955
}
2956
2957
/**
2958
 * Checks whether the current user is a course coach
2959
 * Based on the presence of user in session_rel_user.relation_type (as session general coach, value 3).
2960
 *
2961
 * @return bool True if current user is a course coach
2962
 */
2963
function api_is_session_general_coach()
2964
{
2965
    return Session::read('is_session_general_coach');
2966
}
2967
2968
/**
2969
 * Checks whether the current user is a course tutor
2970
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
2971
 *
2972
 * @return bool True if current user is a course tutor
2973
 */
2974
function api_is_course_tutor()
2975
{
2976
    return Session::read('is_courseTutor');
2977
}
2978
2979
/**
2980
 * @param int $user_id
2981
 * @param int $courseId
2982
 * @param int $session_id
2983
 *
2984
 * @return bool
2985
 */
2986
function api_is_course_session_coach($user_id, $courseId, $session_id)
2987
{
2988
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2989
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2990
2991
    $user_id = (int) $user_id;
2992
    $session_id = (int) $session_id;
2993
    $courseId = (int) $courseId;
2994
2995
    $sql = "SELECT DISTINCT session.id
2996
            FROM $session_table
2997
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2998
            ON session.id = session_rc_ru.session_id
2999
            WHERE
3000
                session_rc_ru.user_id = '".$user_id."'  AND
3001
                session_rc_ru.c_id = '$courseId' AND
3002
                session_rc_ru.status = ".SessionEntity::COURSE_COACH." AND
3003
                session_rc_ru.session_id = '$session_id'";
3004
    $result = Database::query($sql);
3005
3006
    return Database::num_rows($result) > 0;
3007
}
3008
3009
/**
3010
 * Checks whether the current user is a course or session coach.
3011
 *
3012
 * @param int $session_id
3013
 * @param int $courseId
3014
 * @param bool  Check whether we are in student view and, if we are, return false
3015
 * @param int $userId
3016
 *
3017
 * @return bool True if current user is a course or session coach
3018
 */
3019
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
3020
{
3021
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
3022
3023
    if (!empty($session_id)) {
3024
        $session_id = (int) $session_id;
3025
    } else {
3026
        $session_id = api_get_session_id();
3027
    }
3028
3029
    // The student preview was on
3030
    if ($check_student_view && api_is_student_view_active()) {
3031
        return false;
3032
    }
3033
3034
    if (!empty($courseId)) {
3035
        $courseId = (int) $courseId;
3036
    } else {
3037
        $courseId = api_get_course_int_id();
3038
    }
3039
3040
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3041
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3042
    $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3043
    $sessionIsCoach = [];
3044
3045
    if (!empty($courseId)) {
3046
        $sql = "SELECT DISTINCT s.id, title, access_start_date, access_end_date
3047
                FROM $session_table s
3048
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3049
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3050
                WHERE
3051
                    session_rc_ru.c_id = '$courseId' AND
3052
                    session_rc_ru.status =".SessionEntity::COURSE_COACH." AND
3053
                    session_rc_ru.session_id = '$session_id'";
3054
        $result = Database::query($sql);
3055
        $sessionIsCoach = Database::store_result($result);
3056
    }
3057
3058
    if (!empty($session_id)) {
3059
        $sql = "SELECT DISTINCT s.id
3060
                FROM $session_table AS s
3061
                INNER JOIN $tblSessionRelUser sru
3062
                ON s.id = sru.session_id
3063
                WHERE
3064
                    sru.user_id = $userId AND
3065
                    s.id = $session_id AND
3066
                    sru.relation_type = ".SessionEntity::GENERAL_COACH."
3067
                ORDER BY s.access_start_date, s.access_end_date, s.title";
3068
        $result = Database::query($sql);
3069
        if (!empty($sessionIsCoach)) {
3070
            $sessionIsCoach = array_merge(
3071
                $sessionIsCoach,
3072
                Database::store_result($result)
3073
            );
3074
        } else {
3075
            $sessionIsCoach = Database::store_result($result);
3076
        }
3077
    }
3078
3079
    return count($sessionIsCoach) > 0;
3080
}
3081
3082
function api_user_has_role(string $role, ?User $user = null): bool
3083
{
3084
    if (null === $user) {
3085
        $user = api_get_current_user();
3086
    }
3087
3088
    if (null === $user) {
3089
        return false;
3090
    }
3091
3092
    return $user->hasRole($role);
3093
}
3094
3095
function api_is_allowed_in_course(): bool
3096
{
3097
    if (api_is_platform_admin()) {
3098
        return true;
3099
    }
3100
3101
    $user = api_get_current_user();
3102
    if ($user instanceof User) {
3103
        if ($user->hasRole('ROLE_CURRENT_COURSE_SESSION_STUDENT') ||
3104
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
3105
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
3106
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3107
        ) {
3108
            return true;
3109
        }
3110
    }
3111
3112
    return false;
3113
}
3114
3115
/**
3116
 * Checks whether current user is a student boss.
3117
 */
3118
function api_is_student_boss(?User $user = null): bool
3119
{
3120
    return api_user_has_role('ROLE_STUDENT_BOSS', $user);
3121
}
3122
3123
/**
3124
 * Checks whether the current user is a session administrator.
3125
 *
3126
 * @return bool True if current user is a course administrator
3127
 */
3128
function api_is_session_admin(?User $user = null)
3129
{
3130
    return api_user_has_role('ROLE_SESSION_MANAGER', $user);
3131
}
3132
3133
/**
3134
 * Checks whether the current user is a human resources manager.
3135
 *
3136
 * @return bool True if current user is a human resources manager
3137
 */
3138
function api_is_drh()
3139
{
3140
    return api_user_has_role('ROLE_RRHH');
3141
}
3142
3143
/**
3144
 * Checks whether the current user is a student.
3145
 *
3146
 * @return bool True if current user is a human resources manager
3147
 */
3148
function api_is_student()
3149
{
3150
    return api_user_has_role('ROLE_STUDENT');
3151
}
3152
3153
/**
3154
 * Checks whether the current user has the status 'teacher'.
3155
 *
3156
 * @return bool True if current user is a human resources manager
3157
 */
3158
function api_is_teacher()
3159
{
3160
    return api_user_has_role('ROLE_TEACHER');
3161
}
3162
3163
/**
3164
 * Checks whether the current user is a invited user.
3165
 *
3166
 * @return bool
3167
 */
3168
function api_is_invitee()
3169
{
3170
    return api_user_has_role('ROLE_INVITEE');
3171
}
3172
3173
/**
3174
 * This function checks whether a session is assigned into a category.
3175
 *
3176
 * @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...
3177
 * @param string    - category name
3178
 *
3179
 * @return bool - true if is found, otherwise false
3180
 */
3181
function api_is_session_in_category($session_id, $category_name)
3182
{
3183
    $session_id = (int) $session_id;
3184
    $category_name = Database::escape_string($category_name);
3185
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3186
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3187
3188
    $sql = "SELECT 1
3189
            FROM $tbl_session
3190
            WHERE $session_id IN (
3191
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3192
                WHERE
3193
                  s.session_category_id = sc.id AND
3194
                  sc.name LIKE '%$category_name'
3195
            )";
3196
    $rs = Database::query($sql);
3197
3198
    if (Database::num_rows($rs) > 0) {
3199
        return true;
3200
    }
3201
3202
    return false;
3203
}
3204
3205
/**
3206
 * Displays options for switching between student view and course manager view.
3207
 *
3208
 * Changes in version 1.2 (Patrick Cool)
3209
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3210
 * is changed explicitly
3211
 *
3212
 * Changes in version 1.1 (Patrick Cool)
3213
 * student view now works correctly in subfolders of the document tool
3214
 * student view works correctly in the new links tool
3215
 *
3216
 * Example code for using this in your tools:
3217
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3218
 * //   display_tool_view_option($isStudentView);
3219
 * //}
3220
 * //and in later sections, use api_is_allowed_to_edit()
3221
 *
3222
 * @author Roan Embrechts
3223
 * @author Patrick Cool
3224
 * @author Julio Montoya, changes added in Chamilo
3225
 *
3226
 * @version 1.2
3227
 *
3228
 * @todo rewrite code so it is easier to understand
3229
 */
3230
function api_display_tool_view_option()
3231
{
3232
    if ('true' != api_get_setting('student_view_enabled')) {
3233
        return '';
3234
    }
3235
3236
    $sourceurl = '';
3237
    $is_framed = false;
3238
    // Exceptions apply for all multi-frames pages
3239
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3240
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3241
        return '';
3242
    }
3243
3244
    // Uncomment to remove student view link from document view page
3245
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3246
        if (empty($_GET['lp_id'])) {
3247
            return '';
3248
        }
3249
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3250
        $sourceurl = str_replace(
3251
            'lp/lp_header.php',
3252
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3253
            $sourceurl
3254
        );
3255
        //showinframes doesn't handle student view anyway...
3256
        //return '';
3257
        $is_framed = true;
3258
    }
3259
3260
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3261
    if (!$is_framed) {
3262
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3263
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3264
        } else {
3265
            $sourceurl = $_SERVER['REQUEST_URI'];
3266
        }
3267
    }
3268
3269
    $output_string = '';
3270
    if (!empty($_SESSION['studentview'])) {
3271
        if ('studentview' == $_SESSION['studentview']) {
3272
            // We have to remove the isStudentView=true from the $sourceurl
3273
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3274
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3275
            $output_string .= '<a class="btn btn--primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3276
                Display::getMdiIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3277
        } elseif ('teacherview' == $_SESSION['studentview']) {
3278
            // Switching to teacherview
3279
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3280
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3281
            $output_string .= '<a class="btn btn--plain btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3282
                Display::getMdiIcon('eye').' '.get_lang('Switch to student view').'</a>';
3283
        }
3284
    } else {
3285
        $output_string .= '<a class="btn btn--plain btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3286
            Display::getMdiIcon('eye').' '.get_lang('Switch to student view').'</a>';
3287
    }
3288
    $output_string = Security::remove_XSS($output_string);
3289
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3290
3291
    return $html;
3292
}
3293
3294
/**
3295
 * Function that removes the need to directly use is_courseAdmin global in
3296
 * tool scripts. It returns true or false depending on the user's rights in
3297
 * this particular course.
3298
 * Optionally checking for tutor and coach roles here allows us to use the
3299
 * student_view feature altogether with these roles as well.
3300
 *
3301
 * @param bool  Whether to check if the user has the tutor role
3302
 * @param bool  Whether to check if the user has the coach role
3303
 * @param bool  Whether to check if the user has the session coach role
3304
 * @param bool  check the student view or not
3305
 *
3306
 * @author Roan Embrechts
3307
 * @author Patrick Cool
3308
 * @author Julio Montoya
3309
 *
3310
 * @version 1.1, February 2004
3311
 *
3312
 * @return bool true: the user has the rights to edit, false: he does not
3313
 */
3314
function api_is_allowed_to_edit(
3315
    $tutor = false,
3316
    $coach = false,
3317
    $session_coach = false,
3318
    $check_student_view = true
3319
) {
3320
    $allowSessionAdminEdit = 'true' === api_get_setting('session.session_admins_edit_courses_content');
3321
    // Admins can edit anything.
3322
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3323
        //The student preview was on
3324
        if ($check_student_view && api_is_student_view_active()) {
3325
            return false;
3326
        }
3327
3328
        return true;
3329
    }
3330
3331
    $sessionId = api_get_session_id();
3332
3333
    if ($sessionId && 'true' === api_get_setting('session.session_courses_read_only_mode')) {
3334
        $efv = new ExtraFieldValue('course');
3335
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3336
            api_get_course_int_id(),
3337
            'session_courses_read_only_mode'
3338
        );
3339
3340
        if (!empty($lockExrafieldField['value'])) {
3341
            return false;
3342
        }
3343
    }
3344
3345
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3346
    $session_visibility = api_get_session_visibility($sessionId);
3347
    $is_courseAdmin = api_is_course_admin();
3348
3349
    if (!$is_courseAdmin && $tutor) {
3350
        // If we also want to check if the user is a tutor...
3351
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3352
    }
3353
3354
    if (!$is_courseAdmin && $coach) {
3355
        // If we also want to check if the user is a coach...';
3356
        // Check if session visibility is read only for coaches.
3357
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3358
            $is_allowed_coach_to_edit = false;
3359
        }
3360
3361
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3362
            // Check if coach is allowed to edit a course.
3363
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3364
        }
3365
    }
3366
3367
    if (!$is_courseAdmin && $session_coach) {
3368
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3369
    }
3370
3371
    // Check if the student_view is enabled, and if so, if it is activated.
3372
    if ('true' === api_get_setting('student_view_enabled')) {
3373
        $studentView = api_is_student_view_active();
3374
        if (!empty($sessionId)) {
3375
            // Check if session visibility is read only for coaches.
3376
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3377
                $is_allowed_coach_to_edit = false;
3378
            }
3379
3380
            $is_allowed = false;
3381
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3382
                // Check if coach is allowed to edit a course.
3383
                $is_allowed = $is_allowed_coach_to_edit;
3384
            }
3385
            if ($check_student_view) {
3386
                $is_allowed = $is_allowed && false === $studentView;
3387
            }
3388
        } else {
3389
            $is_allowed = $is_courseAdmin;
3390
            if ($check_student_view) {
3391
                $is_allowed = $is_courseAdmin && false === $studentView;
3392
            }
3393
        }
3394
3395
        return $is_allowed;
3396
    } else {
3397
        return $is_courseAdmin;
3398
    }
3399
}
3400
3401
/**
3402
 * Returns true if user is a course coach of at least one course in session.
3403
 *
3404
 * @param int $sessionId
3405
 *
3406
 * @return bool
3407
 */
3408
function api_is_coach_of_course_in_session($sessionId)
3409
{
3410
    if (api_is_platform_admin()) {
3411
        return true;
3412
    }
3413
3414
    $userId = api_get_user_id();
3415
    $courseList = UserManager::get_courses_list_by_session(
3416
        $userId,
3417
        $sessionId
3418
    );
3419
3420
    // Session visibility.
3421
    $visibility = api_get_session_visibility(
3422
        $sessionId,
3423
        null,
3424
        false
3425
    );
3426
3427
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3428
        // Course Coach session visibility.
3429
        $blockedCourseCount = 0;
3430
        $closedVisibilityList = [
3431
            COURSE_VISIBILITY_CLOSED,
3432
            COURSE_VISIBILITY_HIDDEN,
3433
        ];
3434
3435
        foreach ($courseList as $course) {
3436
            // Checking session visibility
3437
            $sessionCourseVisibility = api_get_session_visibility(
3438
                $sessionId,
3439
                $course['real_id']
3440
            );
3441
3442
            $courseIsVisible = !in_array(
3443
                $course['visibility'],
3444
                $closedVisibilityList
3445
            );
3446
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3447
                $blockedCourseCount++;
3448
            }
3449
        }
3450
3451
        // If all courses are blocked then no show in the list.
3452
        if ($blockedCourseCount === count($courseList)) {
3453
            $visibility = SESSION_INVISIBLE;
3454
        } else {
3455
            $visibility = SESSION_VISIBLE;
3456
        }
3457
    }
3458
3459
    switch ($visibility) {
3460
        case SESSION_VISIBLE_READ_ONLY:
3461
        case SESSION_VISIBLE:
3462
        case SESSION_AVAILABLE:
3463
            return true;
3464
            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...
3465
        case SESSION_INVISIBLE:
3466
            return false;
3467
    }
3468
3469
    return false;
3470
}
3471
3472
/**
3473
 * Checks if a student can edit contents in a session depending
3474
 * on the session visibility.
3475
 *
3476
 * @param bool $tutor Whether to check if the user has the tutor role
3477
 * @param bool $coach Whether to check if the user has the coach role
3478
 *
3479
 * @return bool true: the user has the rights to edit, false: he does not
3480
 */
3481
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3482
{
3483
    if (api_is_allowed_to_edit($tutor, $coach)) {
3484
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3485
        return true;
3486
    } else {
3487
        $sessionId = api_get_session_id();
3488
3489
        if (0 == $sessionId) {
3490
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3491
            return true;
3492
        } else {
3493
            // I'm in a session and I'm a student
3494
            // Get the session visibility
3495
            $session_visibility = api_get_session_visibility($sessionId);
3496
            // if 5 the session is still available
3497
            switch ($session_visibility) {
3498
                case SESSION_VISIBLE_READ_ONLY: // 1
3499
                    return false;
3500
                case SESSION_VISIBLE:           // 2
3501
                    return true;
3502
                case SESSION_INVISIBLE:         // 3
3503
                    return false;
3504
                case SESSION_AVAILABLE:         //5
3505
                    return true;
3506
            }
3507
        }
3508
    }
3509
3510
    return false;
3511
}
3512
3513
/**
3514
 * Current user is anon?
3515
 *
3516
 * @return bool true if this user is anonymous, false otherwise
3517
 */
3518
function api_is_anonymous()
3519
{
3520
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED');
3521
}
3522
3523
/**
3524
 * Displays message "You are not allowed here..." and exits the entire script.
3525
 *
3526
 * @param bool $print_headers Whether to print headers (default = false -> does not print them)
3527
 * @param string $message
3528
 * @param int $responseCode
3529
 *
3530
 * @throws Exception
3531
 */
3532
function api_not_allowed(
3533
    $print_headers = false,
3534
    $message = null,
3535
    $responseCode = 0
3536
): never {
3537
    throw new NotAllowedException($message ?: 'You are not allowed', null, $responseCode);
3538
}
3539
3540
/**
3541
 * @param string $languageIsoCode
3542
 *
3543
 * @return string
3544
 */
3545
function languageToCountryIsoCode($languageIsoCode)
3546
{
3547
    $allow = ('true' === api_get_setting('language.language_flags_by_country'));
3548
3549
    // @todo save in DB
3550
    switch ($languageIsoCode) {
3551
        case 'ar':
3552
            $country = 'ae';
3553
            break;
3554
        case 'bs':
3555
            $country = 'ba';
3556
            break;
3557
        case 'ca':
3558
            $country = 'es';
3559
            if ($allow) {
3560
                $country = 'catalan';
3561
            }
3562
            break;
3563
        case 'cs':
3564
            $country = 'cz';
3565
            break;
3566
        case 'da':
3567
            $country = 'dk';
3568
            break;
3569
        case 'el':
3570
            $country = 'ae';
3571
            break;
3572
        case 'en':
3573
            $country = 'gb';
3574
            break;
3575
        case 'eu': // Euskera
3576
            $country = 'es';
3577
            if ($allow) {
3578
                $country = 'basque';
3579
            }
3580
            break;
3581
        case 'gl': // galego
3582
            $country = 'es';
3583
            if ($allow) {
3584
                $country = 'galician';
3585
            }
3586
            break;
3587
        case 'he':
3588
            $country = 'il';
3589
            break;
3590
        case 'ja':
3591
            $country = 'jp';
3592
            break;
3593
        case 'ka':
3594
            $country = 'ge';
3595
            break;
3596
        case 'ko':
3597
            $country = 'kr';
3598
            break;
3599
        case 'ms':
3600
            $country = 'my';
3601
            break;
3602
        case 'pt-BR':
3603
            $country = 'br';
3604
            break;
3605
        case 'qu':
3606
            $country = 'pe';
3607
            break;
3608
        case 'sl':
3609
            $country = 'si';
3610
            break;
3611
        case 'sv':
3612
            $country = 'se';
3613
            break;
3614
        case 'uk': // Ukraine
3615
            $country = 'ua';
3616
            break;
3617
        case 'zh-TW':
3618
        case 'zh':
3619
            $country = 'cn';
3620
            break;
3621
        default:
3622
            $country = $languageIsoCode;
3623
            break;
3624
    }
3625
    $country = strtolower($country);
3626
3627
    return $country;
3628
}
3629
3630
/**
3631
 * Returns a list of all the languages that are made available by the admin.
3632
 *
3633
 * @return array An array with all languages. Structure of the array is
3634
 *               array['name'] = An array with the name of every language
3635
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
3636
 */
3637
function api_get_languages()
3638
{
3639
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3640
    $sql = "SELECT * FROM $table WHERE available='1'
3641
            ORDER BY original_name ASC";
3642
    $result = Database::query($sql);
3643
    $languages = [];
3644
    while ($row = Database::fetch_assoc($result)) {
3645
        $languages[$row['isocode']] = $row['original_name'];
3646
    }
3647
3648
    return $languages;
3649
}
3650
3651
/**
3652
 * Returns the id (the database id) of a language.
3653
 *
3654
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
3655
 *
3656
 * @return int id of the language
3657
 */
3658
function api_get_language_id($language)
3659
{
3660
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3661
    if (empty($language)) {
3662
        return null;
3663
    }
3664
3665
    // We check the language by iscocode
3666
    $langInfo = api_get_language_from_iso($language);
3667
    if (null !== $langInfo && !empty($langInfo->getId())) {
3668
        return $langInfo->getId();
3669
    }
3670
3671
    $language = Database::escape_string($language);
3672
    $sql = "SELECT id FROM $tbl_language
3673
            WHERE english_name = '$language' LIMIT 1";
3674
    $result = Database::query($sql);
3675
    $row = Database::fetch_array($result);
3676
3677
    return $row['id'];
3678
}
3679
3680
/**
3681
 * Get the language information by its id.
3682
 *
3683
 * @param int $languageId
3684
 *
3685
 * @throws Exception
3686
 *
3687
 * @return array
3688
 */
3689
function api_get_language_info($languageId)
3690
{
3691
    if (empty($languageId)) {
3692
        return [];
3693
    }
3694
3695
    $language = Database::getManager()->find(Language::class, $languageId);
3696
3697
    if (!$language) {
3698
        return [];
3699
    }
3700
3701
    return [
3702
        'id' => $language->getId(),
3703
        'original_name' => $language->getOriginalName(),
3704
        'english_name' => $language->getEnglishName(),
3705
        'isocode' => $language->getIsocode(),
3706
        'available' => $language->getAvailable(),
3707
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
3708
    ];
3709
}
3710
3711
/**
3712
 * @param string $code
3713
 *
3714
 * @return Language
3715
 */
3716
function api_get_language_from_iso($code)
3717
{
3718
    $em = Database::getManager();
3719
3720
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
3721
}
3722
3723
/**
3724
 * Returns the name of the visual (CSS) theme to be applied on the current page.
3725
 * The returned name depends on the platform, course or user -wide settings.
3726
 *
3727
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
3728
 */
3729
function api_get_visual_theme()
3730
{
3731
    static $visual_theme;
3732
    if (!isset($visual_theme)) {
3733
        // Get style directly from DB
3734
        /*$styleFromDatabase = api_get_settings_params_simple(
3735
            [
3736
                'variable = ? AND access_url = ?' => [
3737
                    'stylesheets',
3738
                    api_get_current_access_url_id(),
3739
                ],
3740
            ]
3741
        );
3742
3743
        if ($styleFromDatabase) {
3744
            $platform_theme = $styleFromDatabase['selected_value'];
3745
        } else {
3746
            $platform_theme = api_get_setting('stylesheets');
3747
        }*/
3748
        $platform_theme = api_get_setting('stylesheets');
3749
3750
        // Platform's theme.
3751
        $visual_theme = $platform_theme;
3752
        if ('true' == api_get_setting('user_selected_theme')) {
3753
            $user_info = api_get_user_info();
3754
            if (isset($user_info['theme'])) {
3755
                $user_theme = $user_info['theme'];
3756
3757
                if (!empty($user_theme)) {
3758
                    $visual_theme = $user_theme;
3759
                    // User's theme.
3760
                }
3761
            }
3762
        }
3763
3764
        $course_id = api_get_course_id();
3765
        if (!empty($course_id)) {
3766
            if ('true' == api_get_setting('allow_course_theme')) {
3767
                $course_theme = api_get_course_setting('course_theme', $course_id);
3768
3769
                if (!empty($course_theme) && -1 != $course_theme) {
3770
                    if (!empty($course_theme)) {
3771
                        // Course's theme.
3772
                        $visual_theme = $course_theme;
3773
                    }
3774
                }
3775
3776
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
3777
                if (1 == $allow_lp_theme) {
3778
                    /*global $lp_theme_css, $lp_theme_config;
3779
                    // These variables come from the file lp_controller.php.
3780
                    if (!$lp_theme_config) {
3781
                        if (!empty($lp_theme_css)) {
3782
                            // LP's theme.
3783
                            $visual_theme = $lp_theme_css;
3784
                        }
3785
                    }*/
3786
                }
3787
            }
3788
        }
3789
3790
        if (empty($visual_theme)) {
3791
            $visual_theme = 'chamilo';
3792
        }
3793
3794
        /*global $lp_theme_log;
3795
        if ($lp_theme_log) {
3796
            $visual_theme = $platform_theme;
3797
        }*/
3798
    }
3799
3800
    return $visual_theme;
3801
}
3802
3803
/**
3804
 * Returns a list of CSS themes currently available in the CSS folder
3805
 * The folder must have a default.css file.
3806
 *
3807
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
3808
 *
3809
 * @return array list of themes directories from the css folder
3810
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
3811
 */
3812
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
3813
{
3814
    // This configuration value is set by the vchamilo plugin
3815
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
3816
3817
    $readCssFolder = function ($dir) use ($virtualTheme) {
3818
        $finder = new Finder();
3819
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
3820
        $list = [];
3821
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
3822
        foreach ($themes as $theme) {
3823
            $folder = $theme->getFilename();
3824
            // A theme folder is consider if there's a default.css file
3825
            if (!file_exists($theme->getPathname().'/default.css')) {
3826
                continue;
3827
            }
3828
            $name = ucwords(str_replace('_', ' ', $folder));
3829
            if ($folder == $virtualTheme) {
3830
                continue;
3831
            }
3832
            $list[$folder] = $name;
3833
        }
3834
3835
        return $list;
3836
    };
3837
3838
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
3839
    $list = $readCssFolder($dir);
3840
3841
    if (!empty($virtualTheme)) {
3842
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
3843
        if ($getOnlyThemeFromVirtualInstance) {
3844
            return $newList;
3845
        }
3846
        $list = $list + $newList;
3847
        asort($list);
3848
    }
3849
3850
    return $list;
3851
}
3852
3853
/**
3854
 * Find the largest sort value in a given user_course_category
3855
 * This function is used when we are moving a course to a different category
3856
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
3857
 *
3858
 * @param int $courseCategoryId the id of the user_course_category
3859
 * @param int $userId
3860
 *
3861
 * @return int the value of the highest sort of the user_course_category
3862
 */
3863
function api_max_sort_value($courseCategoryId, $userId)
3864
{
3865
    $user = api_get_user_entity($userId);
3866
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
3867
3868
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
3869
}
3870
3871
/**
3872
 * Transforms a number of seconds in hh:mm:ss format.
3873
 *
3874
 * @author Julian Prud'homme
3875
 *
3876
 * @param int    $seconds      number of seconds
3877
 * @param string $space
3878
 * @param bool   $showSeconds
3879
 * @param bool   $roundMinutes
3880
 *
3881
 * @return string the formatted time
3882
 */
3883
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
3884
{
3885
    // $seconds = -1 means that we have wrong data in the db.
3886
    if (-1 == $seconds) {
3887
        return
3888
            get_lang('Unknown').
3889
            Display::getMdiIcon(
3890
                ActionIcon::INFORMATION,
3891
                'ch-tool-icon',
3892
                'align: absmiddle; hspace: 3px',
3893
                ICON_SIZE_SMALL,
3894
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.')
3895
            );
3896
    }
3897
3898
    // How many hours ?
3899
    $hours = floor($seconds / 3600);
3900
3901
    // How many minutes ?
3902
    $min = floor(($seconds - ($hours * 3600)) / 60);
3903
3904
    if ($roundMinutes) {
3905
        if ($min >= 45) {
3906
            $min = 45;
3907
        }
3908
3909
        if ($min >= 30 && $min <= 44) {
3910
            $min = 30;
3911
        }
3912
3913
        if ($min >= 15 && $min <= 29) {
3914
            $min = 15;
3915
        }
3916
3917
        if ($min >= 0 && $min <= 14) {
3918
            $min = 0;
3919
        }
3920
    }
3921
3922
    // How many seconds
3923
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
3924
3925
    if ($hours < 10) {
3926
        $hours = "0$hours";
3927
    }
3928
3929
    if ($sec < 10) {
3930
        $sec = "0$sec";
3931
    }
3932
3933
    if ($min < 10) {
3934
        $min = "0$min";
3935
    }
3936
3937
    $seconds = '';
3938
    if ($showSeconds) {
3939
        $seconds = $space.$sec;
3940
    }
3941
3942
    return $hours.$space.$min.$seconds;
3943
}
3944
3945
/**
3946
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3947
 * The return value is based on the platform administrator's setting
3948
 * "Administration > Configuration settings > Security > Permissions for new directories".
3949
 *
3950
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
3951
 */
3952
function api_get_permissions_for_new_directories()
3953
{
3954
    static $permissions;
3955
    if (!isset($permissions)) {
3956
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
3957
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
3958
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
3959
    }
3960
3961
    return $permissions;
3962
}
3963
3964
/**
3965
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3966
 * The return value is based on the platform administrator's setting
3967
 * "Administration > Configuration settings > Security > Permissions for new files".
3968
 *
3969
 * @return int returns the permissions in the format
3970
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
3971
 */
3972
function api_get_permissions_for_new_files()
3973
{
3974
    static $permissions;
3975
    if (!isset($permissions)) {
3976
        $permissions = trim(api_get_setting('permissions_for_new_files'));
3977
        // The default value 0666 is according to that in the platform
3978
        // administration panel after fresh system installation.
3979
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
3980
    }
3981
3982
    return $permissions;
3983
}
3984
3985
/**
3986
 * Deletes a file, or a folder and its contents.
3987
 *
3988
 * @author      Aidan Lister <[email protected]>
3989
 *
3990
 * @version     1.0.3
3991
 *
3992
 * @param string $dirname Directory to delete
3993
 * @param       bool     Deletes only the content or not
3994
 * @param bool $strict if one folder/file fails stop the loop
3995
 *
3996
 * @return bool Returns TRUE on success, FALSE on failure
3997
 *
3998
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
3999
 *
4000
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4001
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4002
 */
4003
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4004
{
4005
    $res = true;
4006
    // A sanity check.
4007
    if (!file_exists($dirname)) {
4008
        return false;
4009
    }
4010
    $php_errormsg = '';
4011
    // Simple delete for a file.
4012
    if (is_file($dirname) || is_link($dirname)) {
4013
        $res = unlink($dirname);
4014
        if (false === $res) {
4015
            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);
4016
        }
4017
4018
        return $res;
4019
    }
4020
4021
    // Loop through the folder.
4022
    $dir = dir($dirname);
4023
    // A sanity check.
4024
    $is_object_dir = is_object($dir);
4025
    if ($is_object_dir) {
4026
        while (false !== $entry = $dir->read()) {
4027
            // Skip pointers.
4028
            if ('.' == $entry || '..' == $entry) {
4029
                continue;
4030
            }
4031
4032
            // Recurse.
4033
            if ($strict) {
4034
                $result = rmdirr("$dirname/$entry");
4035
                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...
4036
                    $res = false;
4037
                    break;
4038
                }
4039
            } else {
4040
                rmdirr("$dirname/$entry");
4041
            }
4042
        }
4043
    }
4044
4045
    // Clean up.
4046
    if ($is_object_dir) {
4047
        $dir->close();
4048
    }
4049
4050
    if (false == $delete_only_content_in_folder) {
4051
        $res = rmdir($dirname);
4052
        if (false === $res) {
4053
            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);
4054
        }
4055
    }
4056
4057
    return $res;
4058
}
4059
4060
// TODO: This function is to be simplified. File access modes to be implemented.
4061
/**
4062
 * function adapted from a php.net comment
4063
 * copy recursively a folder.
4064
 *
4065
 * @param the source folder
4066
 * @param the dest folder
4067
 * @param an array of excluded file_name (without extension)
4068
 * @param copied_files the returned array of copied files
4069
 * @param string $source
4070
 * @param string $dest
4071
 */
4072
function copyr($source, $dest, $exclude = [], $copied_files = [])
4073
{
4074
    if (empty($dest)) {
4075
        return false;
4076
    }
4077
    // Simple copy for a file
4078
    if (is_file($source)) {
4079
        $path_info = pathinfo($source);
4080
        if (!in_array($path_info['filename'], $exclude)) {
4081
            copy($source, $dest);
4082
        }
4083
4084
        return true;
4085
    } elseif (!is_dir($source)) {
4086
        //then source is not a dir nor a file, return
4087
        return false;
4088
    }
4089
4090
    // Make destination directory.
4091
    if (!is_dir($dest)) {
4092
        mkdir($dest, api_get_permissions_for_new_directories());
4093
    }
4094
4095
    // Loop through the folder.
4096
    $dir = dir($source);
4097
    while (false !== $entry = $dir->read()) {
4098
        // Skip pointers
4099
        if ('.' == $entry || '..' == $entry) {
4100
            continue;
4101
        }
4102
4103
        // Deep copy directories.
4104
        if ($dest !== "$source/$entry") {
4105
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4106
        }
4107
    }
4108
    // Clean up.
4109
    $dir->close();
4110
4111
    return true;
4112
}
4113
4114
/**
4115
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4116
 * Documentation header to be added here.
4117
 *
4118
 * @param string $pathname
4119
 * @param string $base_path_document
4120
 * @param int    $session_id
4121
 *
4122
 * @return mixed True if directory already exists, false if a file already exists at
4123
 *               the destination and null if everything goes according to plan
4124
 */
4125
function copy_folder_course_session(
4126
    $pathname,
4127
    $base_path_document,
4128
    $session_id,
4129
    $course_info,
4130
    $document,
4131
    $source_course_id
4132
) {
4133
    $table = Database::get_course_table(TABLE_DOCUMENT);
4134
    $session_id = intval($session_id);
4135
    $source_course_id = intval($source_course_id);
4136
4137
    // Check whether directory already exists.
4138
    if (is_dir($pathname) || empty($pathname)) {
4139
        return true;
4140
    }
4141
4142
    // Ensure that a file with the same name does not already exist.
4143
    if (is_file($pathname)) {
4144
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4145
4146
        return false;
4147
    }
4148
4149
    $course_id = $course_info['real_id'];
4150
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4151
    $new_pathname = $base_path_document;
4152
    $path = '';
4153
4154
    foreach ($folders as $folder) {
4155
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4156
        $path .= DIRECTORY_SEPARATOR.$folder;
4157
4158
        if (!file_exists($new_pathname)) {
4159
            $path = Database::escape_string($path);
4160
4161
            $sql = "SELECT * FROM $table
4162
                    WHERE
4163
                        c_id = $source_course_id AND
4164
                        path = '$path' AND
4165
                        filetype = 'folder' AND
4166
                        session_id = '$session_id'";
4167
            $rs1 = Database::query($sql);
4168
            $num_rows = Database::num_rows($rs1);
4169
4170
            if (0 == $num_rows) {
4171
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4172
4173
                // Insert new folder with destination session_id.
4174
                $params = [
4175
                    'c_id' => $course_id,
4176
                    'path' => $path,
4177
                    'comment' => $document->comment,
4178
                    'title' => basename($new_pathname),
4179
                    'filetype' => 'folder',
4180
                    'size' => '0',
4181
                    'session_id' => $session_id,
4182
                ];
4183
                Database::insert($table, $params);
4184
            }
4185
        }
4186
    } // en foreach
4187
}
4188
4189
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4190
/**
4191
 * @param string $path
4192
 */
4193
function api_chmod_R($path, $filemode)
4194
{
4195
    if (!is_dir($path)) {
4196
        return chmod($path, $filemode);
4197
    }
4198
4199
    $handler = opendir($path);
4200
    while ($file = readdir($handler)) {
4201
        if ('.' != $file && '..' != $file) {
4202
            $fullpath = "$path/$file";
4203
            if (!is_dir($fullpath)) {
4204
                if (!chmod($fullpath, $filemode)) {
4205
                    return false;
4206
                }
4207
            } else {
4208
                if (!api_chmod_R($fullpath, $filemode)) {
4209
                    return false;
4210
                }
4211
            }
4212
        }
4213
    }
4214
4215
    closedir($handler);
4216
4217
    return chmod($path, $filemode);
4218
}
4219
4220
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4221
/**
4222
 * Parse info file format. (e.g: file.info).
4223
 *
4224
 * Files should use an ini-like format to specify values.
4225
 * White-space generally doesn't matter, except inside values.
4226
 * e.g.
4227
 *
4228
 * @verbatim
4229
 *   key = value
4230
 *   key = "value"
4231
 *   key = 'value'
4232
 *   key = "multi-line
4233
 *
4234
 *   value"
4235
 *   key = 'multi-line
4236
 *
4237
 *   value'
4238
 *   key
4239
 *   =
4240
 *   'value'
4241
 * @endverbatim
4242
 *
4243
 * Arrays are created using a GET-like syntax:
4244
 *
4245
 * @verbatim
4246
 *   key[] = "numeric array"
4247
 *   key[index] = "associative array"
4248
 *   key[index][] = "nested numeric array"
4249
 *   key[index][index] = "nested associative array"
4250
 * @endverbatim
4251
 *
4252
 * PHP constants are substituted in, but only when used as the entire value:
4253
 *
4254
 * Comments should start with a semi-colon at the beginning of a line.
4255
 *
4256
 * This function is NOT for placing arbitrary module-specific settings. Use
4257
 * variable_get() and variable_set() for that.
4258
 *
4259
 * Information stored in the module.info file:
4260
 * - name: The real name of the module for display purposes.
4261
 * - description: A brief description of the module.
4262
 * - dependencies: An array of shortnames of other modules this module depends on.
4263
 * - package: The name of the package of modules this module belongs to.
4264
 *
4265
 * Example of .info file:
4266
 * <code>
4267
 * @verbatim
4268
 *   name = Forum
4269
 *   description = Enables threaded discussions about general topics.
4270
 *   dependencies[] = taxonomy
4271
 *   dependencies[] = comment
4272
 *   package = Core - optional
4273
 *   version = VERSION
4274
 * @endverbatim
4275
 * </code>
4276
 *
4277
 * @param string $filename
4278
 *                         The file we are parsing. Accepts file with relative or absolute path.
4279
 *
4280
 * @return
4281
 *   The info array
4282
 */
4283
function api_parse_info_file($filename)
4284
{
4285
    $info = [];
4286
4287
    if (!file_exists($filename)) {
4288
        return $info;
4289
    }
4290
4291
    $data = file_get_contents($filename);
4292
    if (preg_match_all('
4293
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4294
        ((?:
4295
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4296
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4297
        )+?)
4298
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4299
        (?:
4300
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4301
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4302
          ([^\r\n]*?)                   # Non-quoted string
4303
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4304
        @msx', $data, $matches, PREG_SET_ORDER)) {
4305
        $key = $value1 = $value2 = $value3 = '';
4306
        foreach ($matches as $match) {
4307
            // Fetch the key and value string.
4308
            $i = 0;
4309
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4310
                $$var = isset($match[++$i]) ? $match[$i] : '';
4311
            }
4312
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4313
4314
            // Parse array syntax.
4315
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4316
            $last = array_pop($keys);
4317
            $parent = &$info;
4318
4319
            // Create nested arrays.
4320
            foreach ($keys as $key) {
4321
                if ('' == $key) {
4322
                    $key = count($parent);
4323
                }
4324
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4325
                    $parent[$key] = [];
4326
                }
4327
                $parent = &$parent[$key];
4328
            }
4329
4330
            // Handle PHP constants.
4331
            if (defined($value)) {
4332
                $value = constant($value);
4333
            }
4334
4335
            // Insert actual value.
4336
            if ('' == $last) {
4337
                $last = count($parent);
4338
            }
4339
            $parent[$last] = $value;
4340
        }
4341
    }
4342
4343
    return $info;
4344
}
4345
4346
/**
4347
 * Gets Chamilo version from the configuration files.
4348
 *
4349
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4350
 */
4351
function api_get_version()
4352
{
4353
    return (string) api_get_configuration_value('system_version');
4354
}
4355
4356
/**
4357
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4358
 *
4359
 * @return string
4360
 */
4361
function api_get_software_name()
4362
{
4363
    $name = api_get_configuration_value('software_name');
4364
    if (!empty($name)) {
4365
        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...
4366
    } else {
4367
        return 'Chamilo';
4368
    }
4369
}
4370
4371
function api_get_status_list()
4372
{
4373
    $list = [];
4374
    // Table of status
4375
    $list[COURSEMANAGER] = 'teacher'; // 1
4376
    $list[SESSIONADMIN] = 'session_admin'; // 3
4377
    $list[DRH] = 'drh'; // 4
4378
    $list[STUDENT] = 'user'; // 5
4379
    $list[ANONYMOUS] = 'anonymous'; // 6
4380
    $list[INVITEE] = 'invited'; // 20
4381
4382
    return $list;
4383
}
4384
4385
/**
4386
 * Checks whether status given in parameter exists in the platform.
4387
 *
4388
 * @param mixed the status (can be either int either string)
4389
 *
4390
 * @return bool if the status exists, else returns false
4391
 */
4392
function api_status_exists($status_asked)
4393
{
4394
    $list = api_get_status_list();
4395
4396
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4397
}
4398
4399
/**
4400
 * Checks whether status given in parameter exists in the platform. The function
4401
 * returns the status ID or false if it does not exist, but given the fact there
4402
 * is no "0" status, the return value can be checked against
4403
 * if(api_status_key()) to know if it exists.
4404
 *
4405
 * @param   mixed   The status (can be either int or string)
4406
 *
4407
 * @return mixed Status ID if exists, false otherwise
4408
 */
4409
function api_status_key($status)
4410
{
4411
    $list = api_get_status_list();
4412
4413
    return isset($list[$status]) ? $status : array_search($status, $list);
4414
}
4415
4416
/**
4417
 * Gets the status langvars list.
4418
 *
4419
 * @return string[] the list of status with their translations
4420
 */
4421
function api_get_status_langvars()
4422
{
4423
    return [
4424
        COURSEMANAGER => get_lang('Teacher'),
4425
        SESSIONADMIN => get_lang('SessionsAdmin'),
4426
        DRH => get_lang('Human Resources Manager'),
4427
        STUDENT => get_lang('Learner'),
4428
        ANONYMOUS => get_lang('Anonymous'),
4429
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4430
        INVITEE => get_lang('Invited'),
4431
    ];
4432
}
4433
4434
/**
4435
 * The function that retrieves all the possible settings for a certain config setting.
4436
 *
4437
 * @author Patrick Cool <[email protected]>, Ghent University
4438
 */
4439
function api_get_settings_options($var)
4440
{
4441
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4442
    $var = Database::escape_string($var);
4443
    $sql = "SELECT * FROM $table_settings_options
4444
            WHERE variable = '$var'
4445
            ORDER BY id";
4446
    $result = Database::query($sql);
4447
    $settings_options_array = [];
4448
    while ($row = Database::fetch_assoc($result)) {
4449
        $settings_options_array[] = $row;
4450
    }
4451
4452
    return $settings_options_array;
4453
}
4454
4455
/**
4456
 * @param array $params
4457
 */
4458
function api_set_setting_option($params)
4459
{
4460
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4461
    if (empty($params['id'])) {
4462
        Database::insert($table, $params);
4463
    } else {
4464
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4465
    }
4466
}
4467
4468
/**
4469
 * @param array $params
4470
 */
4471
function api_set_setting_simple($params)
4472
{
4473
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4474
    $url_id = api_get_current_access_url_id();
4475
4476
    if (empty($params['id'])) {
4477
        $params['access_url'] = $url_id;
4478
        Database::insert($table, $params);
4479
    } else {
4480
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4481
    }
4482
}
4483
4484
/**
4485
 * @param int $id
4486
 */
4487
function api_delete_setting_option($id)
4488
{
4489
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4490
    if (!empty($id)) {
4491
        Database::delete($table, ['id = ? ' => $id]);
4492
    }
4493
}
4494
4495
/**
4496
 * Sets a platform configuration setting to a given value.
4497
 *
4498
 * @param string    The variable we want to update
4499
 * @param string    The value we want to record
4500
 * @param string    The sub-variable if any (in most cases, this will remain null)
4501
 * @param string    The category if any (in most cases, this will remain null)
4502
 * @param int       The access_url for which this parameter is valid
4503
 * @param string $cat
4504
 *
4505
 * @return bool|null
4506
 */
4507
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
4508
{
4509
    if (empty($var)) {
4510
        return false;
4511
    }
4512
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4513
    $var = Database::escape_string($var);
4514
    $value = Database::escape_string($value);
4515
    $access_url = (int) $access_url;
4516
    if (empty($access_url)) {
4517
        $access_url = 1;
4518
    }
4519
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
4520
    if (!empty($subvar)) {
4521
        $subvar = Database::escape_string($subvar);
4522
        $select .= " AND subkey = '$subvar'";
4523
    }
4524
    if (!empty($cat)) {
4525
        $cat = Database::escape_string($cat);
4526
        $select .= " AND category = '$cat'";
4527
    }
4528
    if ($access_url > 1) {
4529
        $select .= " AND access_url = $access_url";
4530
    } else {
4531
        $select .= " AND access_url = 1 ";
4532
    }
4533
4534
    $res = Database::query($select);
4535
    if (Database::num_rows($res) > 0) {
4536
        // Found item for this access_url.
4537
        $row = Database::fetch_array($res);
4538
        $sql = "UPDATE $t_settings SET selected_value = '$value'
4539
                WHERE id = ".$row['id'];
4540
        Database::query($sql);
4541
    } else {
4542
        // Item not found for this access_url, we have to check if it exist with access_url = 1
4543
        $select = "SELECT * FROM $t_settings
4544
                   WHERE variable = '$var' AND access_url = 1 ";
4545
        // Just in case
4546
        if (1 == $access_url) {
4547
            if (!empty($subvar)) {
4548
                $select .= " AND subkey = '$subvar'";
4549
            }
4550
            if (!empty($cat)) {
4551
                $select .= " AND category = '$cat'";
4552
            }
4553
            $res = Database::query($select);
4554
            if (Database::num_rows($res) > 0) {
4555
                // We have a setting for access_url 1, but none for the current one, so create one.
4556
                $row = Database::fetch_array($res);
4557
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
4558
                        VALUES
4559
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4560
                    "'".$row['type']."','".$row['category']."',".
4561
                    "'$value','".$row['title']."',".
4562
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4563
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
4564
                Database::query($insert);
4565
            } else {
4566
                // Such a setting does not exist.
4567
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
4568
            }
4569
        } else {
4570
            // Other access url.
4571
            if (!empty($subvar)) {
4572
                $select .= " AND subkey = '$subvar'";
4573
            }
4574
            if (!empty($cat)) {
4575
                $select .= " AND category = '$cat'";
4576
            }
4577
            $res = Database::query($select);
4578
4579
            if (Database::num_rows($res) > 0) {
4580
                // We have a setting for access_url 1, but none for the current one, so create one.
4581
                $row = Database::fetch_array($res);
4582
                if (1 == $row['access_url_changeable']) {
4583
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
4584
                            ('".$row['variable']."',".
4585
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4586
                        "'".$row['type']."','".$row['category']."',".
4587
                        "'$value','".$row['title']."',".
4588
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
4589
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4590
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
4591
                    Database::query($insert);
4592
                }
4593
            } else { // Such a setting does not exist.
4594
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
4595
            }
4596
        }
4597
    }
4598
}
4599
4600
/**
4601
 * Sets a whole category of settings to one specific value.
4602
 *
4603
 * @param string    Category
4604
 * @param string    Value
4605
 * @param int       Access URL. Optional. Defaults to 1
4606
 * @param array     Optional array of filters on field type
4607
 * @param string $category
4608
 * @param string $value
4609
 *
4610
 * @return bool
4611
 */
4612
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
4613
{
4614
    if (empty($category)) {
4615
        return false;
4616
    }
4617
    $category = Database::escape_string($category);
4618
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4619
    $access_url = (int) $access_url;
4620
    if (empty($access_url)) {
4621
        $access_url = 1;
4622
    }
4623
    if (isset($value)) {
4624
        $value = Database::escape_string($value);
4625
        $sql = "UPDATE $t_s SET selected_value = '$value'
4626
                WHERE category = '$category' AND access_url = $access_url";
4627
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4628
            $sql .= " AND ( ";
4629
            $i = 0;
4630
            foreach ($fieldtype as $type) {
4631
                if ($i > 0) {
4632
                    $sql .= ' OR ';
4633
                }
4634
                $type = Database::escape_string($type);
4635
                $sql .= " type='".$type."' ";
4636
                $i++;
4637
            }
4638
            $sql .= ")";
4639
        }
4640
        $res = Database::query($sql);
4641
4642
        return false !== $res;
4643
    } else {
4644
        $sql = "UPDATE $t_s SET selected_value = NULL
4645
                WHERE category = '$category' AND access_url = $access_url";
4646
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4647
            $sql .= " AND ( ";
4648
            $i = 0;
4649
            foreach ($fieldtype as $type) {
4650
                if ($i > 0) {
4651
                    $sql .= ' OR ';
4652
                }
4653
                $type = Database::escape_string($type);
4654
                $sql .= " type='".$type."' ";
4655
                $i++;
4656
            }
4657
            $sql .= ")";
4658
        }
4659
        $res = Database::query($sql);
4660
4661
        return false !== $res;
4662
    }
4663
}
4664
4665
/**
4666
 * Gets all available access urls in an array (as in the database).
4667
 *
4668
 * @return array An array of database records
4669
 */
4670
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
4671
{
4672
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4673
    $from = (int) $from;
4674
    $to = (int) $to;
4675
    $order = Database::escape_string($order);
4676
    $direction = Database::escape_string($direction);
4677
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
4678
    $sql = "SELECT id, url, description, active, created_by, tms
4679
            FROM $table
4680
            ORDER BY `$order` $direction
4681
            LIMIT $to OFFSET $from";
4682
    $res = Database::query($sql);
4683
4684
    return Database::store_result($res);
4685
}
4686
4687
/**
4688
 * Gets the access url info in an array.
4689
 *
4690
 * @param int  $id            Id of the access url
4691
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
4692
 *
4693
 * @return array All the info (url, description, active, created_by, tms)
4694
 *               from the access_url table
4695
 *
4696
 * @author Julio Montoya
4697
 */
4698
function api_get_access_url($id, $returnDefault = true)
4699
{
4700
    static $staticResult;
4701
    $id = (int) $id;
4702
4703
    if (isset($staticResult[$id])) {
4704
        $result = $staticResult[$id];
4705
    } else {
4706
        // Calling the Database:: library dont work this is handmade.
4707
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4708
        $sql = "SELECT url, description, active, created_by, tms
4709
                FROM $table_access_url WHERE id = '$id' ";
4710
        $res = Database::query($sql);
4711
        $result = @Database::fetch_array($res);
4712
        $staticResult[$id] = $result;
4713
    }
4714
4715
    // If the result url is 'http://localhost/' (the default) and the root_web
4716
    // (=current url) is different, and the $id is = 1 (which might mean
4717
    // api_get_current_access_url_id() returned 1 by default), then return the
4718
    // root_web setting instead of the current URL
4719
    // This is provided as an option to avoid breaking the storage of URL-specific
4720
    // homepages in home/localhost/
4721
    if (1 === $id && false === $returnDefault) {
4722
        $currentUrl = api_get_current_access_url_id();
4723
        // only do this if we are on the main URL (=1), otherwise we could get
4724
        // information on another URL instead of the one asked as parameter
4725
        if (1 === $currentUrl) {
4726
            $rootWeb = api_get_path(WEB_PATH);
4727
            $default = AccessUrl::DEFAULT_ACCESS_URL;
4728
            if ($result['url'] === $default && $rootWeb != $default) {
4729
                $result['url'] = $rootWeb;
4730
            }
4731
        }
4732
    }
4733
4734
    return $result;
4735
}
4736
4737
/**
4738
 * Gets all the current settings for a specific access url.
4739
 *
4740
 * @param string    The category, if any, that we want to get
4741
 * @param string    Whether we want a simple list (display a category) or
4742
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
4743
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
4744
 *
4745
 * @return array Array of database results for the current settings of the current access URL
4746
 */
4747
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
4748
{
4749
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4750
    $access_url = (int) $access_url;
4751
    $where_condition = '';
4752
    if (1 == $url_changeable) {
4753
        $where_condition = " AND access_url_changeable= '1' ";
4754
    }
4755
    if (empty($access_url) || -1 == $access_url) {
4756
        $access_url = 1;
4757
    }
4758
    $sql = "SELECT * FROM $table
4759
            WHERE access_url = $access_url  $where_condition ";
4760
4761
    if (!empty($cat)) {
4762
        $cat = Database::escape_string($cat);
4763
        $sql .= " AND category='$cat' ";
4764
    }
4765
    if ('group' == $ordering) {
4766
        $sql .= " ORDER BY id ASC";
4767
    } else {
4768
        $sql .= " ORDER BY 1,2 ASC";
4769
    }
4770
    $result = Database::query($sql);
4771
    if (null === $result) {
4772
        $result = [];
4773
        return $result;
4774
    }
4775
    $result = Database::store_result($result, 'ASSOC');
4776
4777
    return $result;
4778
}
4779
4780
/**
4781
 * @param string $value       The value we want to record
4782
 * @param string $variable    The variable name we want to insert
4783
 * @param string $subKey      The subkey for the variable we want to insert
4784
 * @param string $type        The type for the variable we want to insert
4785
 * @param string $category    The category for the variable we want to insert
4786
 * @param string $title       The title
4787
 * @param string $comment     The comment
4788
 * @param string $scope       The scope
4789
 * @param string $subKeyText  The subkey text
4790
 * @param int    $accessUrlId The access_url for which this parameter is valid
4791
 * @param int    $visibility  The changeability of this setting for non-master urls
4792
 *
4793
 * @return int The setting ID
4794
 */
4795
function api_add_setting(
4796
    $value,
4797
    $variable,
4798
    $subKey = '',
4799
    $type = 'textfield',
4800
    $category = '',
4801
    $title = '',
4802
    $comment = '',
4803
    $scope = '',
4804
    $subKeyText = '',
4805
    $accessUrlId = 1,
4806
    $visibility = 0
4807
) {
4808
    $em = Database::getManager();
4809
4810
    $settingRepo = $em->getRepository(SettingsCurrent::class);
4811
    $accessUrlId = (int) $accessUrlId ?: 1;
4812
4813
    if (is_array($value)) {
4814
        $value = serialize($value);
4815
    } else {
4816
        $value = trim($value);
4817
    }
4818
4819
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
4820
4821
    if (!empty($subKey)) {
4822
        $criteria['subkey'] = $subKey;
4823
    }
4824
4825
    // Check if this variable doesn't exist already
4826
    /** @var SettingsCurrent $setting */
4827
    $setting = $settingRepo->findOneBy($criteria);
4828
4829
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
4830
        $setting->setSelectedValue($value);
4831
4832
        $em->persist($setting);
4833
        $em->flush();
4834
4835
        return $setting->getId();
4836
    }
4837
4838
    // Item not found for this access_url, we have to check if the whole thing is missing
4839
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
4840
    $setting = new SettingsCurrent();
4841
    $url = api_get_url_entity();
4842
4843
    $setting
4844
        ->setVariable($variable)
4845
        ->setSelectedValue($value)
4846
        ->setType($type)
4847
        ->setCategory($category)
4848
        ->setSubkey($subKey)
4849
        ->setTitle($title)
4850
        ->setComment($comment)
4851
        ->setScope($scope)
4852
        ->setSubkeytext($subKeyText)
4853
        ->setUrl(api_get_url_entity())
4854
        ->setAccessUrlChangeable($visibility);
4855
4856
    $em->persist($setting);
4857
    $em->flush();
4858
4859
    return $setting->getId();
4860
}
4861
4862
/**
4863
 * Checks wether a user can or can't view the contents of a course.
4864
 *
4865
 * @deprecated use CourseManager::is_user_subscribed_in_course
4866
 *
4867
 * @param int $userid User id or NULL to get it from $_SESSION
4868
 * @param int $cid    course id to check whether the user is allowed
4869
 *
4870
 * @return bool
4871
 */
4872
function api_is_course_visible_for_user($userid = null, $cid = null)
4873
{
4874
    if (null === $userid) {
4875
        $userid = api_get_user_id();
4876
    }
4877
    if (empty($userid) || strval(intval($userid)) != $userid) {
4878
        if (api_is_anonymous()) {
4879
            $userid = api_get_anonymous_id();
4880
        } else {
4881
            return false;
4882
        }
4883
    }
4884
    $cid = Database::escape_string($cid);
4885
4886
    $courseInfo = api_get_course_info($cid);
4887
    $courseId = $courseInfo['real_id'];
4888
    $is_platformAdmin = api_is_platform_admin();
4889
4890
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
4891
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
4892
4893
    $sql = "SELECT
4894
                $course_cat_table.code AS category_code,
4895
                $course_table.visibility,
4896
                $course_table.code,
4897
                $course_cat_table.code
4898
            FROM $course_table
4899
            LEFT JOIN $course_cat_table
4900
                ON $course_table.category_id = $course_cat_table.id
4901
            WHERE
4902
                $course_table.code = '$cid'
4903
            LIMIT 1";
4904
4905
    $result = Database::query($sql);
4906
4907
    if (Database::num_rows($result) > 0) {
4908
        $visibility = Database::fetch_array($result);
4909
        $visibility = $visibility['visibility'];
4910
    } else {
4911
        $visibility = 0;
4912
    }
4913
    // Shortcut permissions in case the visibility is "open to the world".
4914
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
4915
        return true;
4916
    }
4917
4918
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4919
4920
    $sql = "SELECT
4921
                is_tutor, status
4922
            FROM $tbl_course_user
4923
            WHERE
4924
                user_id  = '$userid' AND
4925
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
4926
                c_id = $courseId
4927
            LIMIT 1";
4928
4929
    $result = Database::query($sql);
4930
4931
    if (Database::num_rows($result) > 0) {
4932
        // This user has got a recorded state for this course.
4933
        $cuData = Database::fetch_array($result);
4934
        $is_courseMember = true;
4935
        $is_courseAdmin = (1 == $cuData['status']);
4936
    }
4937
4938
    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...
4939
        // This user has no status related to this course.
4940
        // Is it the session coach or the session admin?
4941
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4942
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4943
        $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4944
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4945
4946
        $sql = "SELECT sru_2.user_id AS session_admin_id, sru_1.user_id AS session_coach_id
4947
                FROM $tbl_session AS s
4948
                INNER JOIN $tblSessionRelUser sru_1
4949
                ON (sru_1.session_id = s.id AND sru_1.relation_type = ".SessionEntity::GENERAL_COACH.")
4950
                INNER JOIN $tblSessionRelUser sru_2
4951
                ON (sru_2.session_id = s.id AND sru_2.relation_type = ".SessionEntity::SESSION_ADMIN.")
4952
                INNER JOIN $tbl_session_course src
4953
                ON (src.session_id = s.id AND src.c_id = $courseId)";
4954
4955
        $result = Database::query($sql);
4956
        $row = Database::store_result($result);
4957
        $sessionAdminsId = array_column($row, 'session_admin_id');
4958
        $sessionCoachesId = array_column($row, 'session_coach_id');
4959
4960
        if (in_array($userid, $sessionCoachesId)) {
4961
            $is_courseMember = true;
4962
            $is_courseAdmin = false;
4963
        } elseif (in_array($userid, $sessionAdminsId)) {
4964
            $is_courseMember = false;
4965
            $is_courseAdmin = false;
4966
        } else {
4967
            // Check if the current user is the course coach.
4968
            $sql = "SELECT 1
4969
                    FROM $tbl_session_course
4970
                    WHERE session_rel_course.c_id = '$courseId'
4971
                    AND session_rel_course.id_coach = '$userid'
4972
                    LIMIT 1";
4973
4974
            $result = Database::query($sql);
4975
4976
            //if ($row = Database::fetch_array($result)) {
4977
            if (Database::num_rows($result) > 0) {
4978
                $is_courseMember = true;
4979
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4980
4981
                $sql = "SELECT status FROM $tbl_user
4982
                        WHERE id = $userid
4983
                        LIMIT 1";
4984
4985
                $result = Database::query($sql);
4986
4987
                if (1 == Database::result($result, 0, 0)) {
4988
                    $is_courseAdmin = true;
4989
                } else {
4990
                    $is_courseAdmin = false;
4991
                }
4992
            } else {
4993
                // Check if the user is a student is this session.
4994
                $sql = "SELECT  id
4995
                        FROM $tbl_session_course_user
4996
                        WHERE
4997
                            user_id  = '$userid' AND
4998
                            c_id = '$courseId'
4999
                        LIMIT 1";
5000
5001
                if (Database::num_rows($result) > 0) {
5002
                    // This user haa got a recorded state for this course.
5003
                    while ($row = Database::fetch_array($result)) {
5004
                        $is_courseMember = true;
5005
                        $is_courseAdmin = false;
5006
                    }
5007
                }
5008
            }
5009
        }
5010
    }
5011
5012
    switch ($visibility) {
5013
        case Course::OPEN_WORLD:
5014
            return true;
5015
        case Course::OPEN_PLATFORM:
5016
            return isset($userid);
5017
        case Course::REGISTERED:
5018
        case Course::CLOSED:
5019
            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...
5020
        case Course::HIDDEN:
5021
            return $is_platformAdmin;
5022
    }
5023
5024
    return false;
5025
}
5026
5027
/**
5028
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5029
 *
5030
 * @param string the tool of the element
5031
 * @param int the element id in database
5032
 * @param int the session_id to compare with element session id
5033
 *
5034
 * @return bool true if the element is in the session, false else
5035
 */
5036
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5037
{
5038
    if (is_null($session_id)) {
5039
        $session_id = api_get_session_id();
5040
    }
5041
5042
    $element_id = (int) $element_id;
5043
5044
    if (empty($element_id)) {
5045
        return false;
5046
    }
5047
5048
    // Get information to build query depending of the tool.
5049
    switch ($tool) {
5050
        case TOOL_SURVEY:
5051
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5052
            $key_field = 'survey_id';
5053
            break;
5054
        case TOOL_ANNOUNCEMENT:
5055
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5056
            $key_field = 'id';
5057
            break;
5058
        case TOOL_AGENDA:
5059
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5060
            $key_field = 'id';
5061
            break;
5062
        case TOOL_GROUP:
5063
            $table_tool = Database::get_course_table(TABLE_GROUP);
5064
            $key_field = 'id';
5065
            break;
5066
        default:
5067
            return false;
5068
    }
5069
    $course_id = api_get_course_int_id();
5070
5071
    $sql = "SELECT session_id FROM $table_tool
5072
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5073
    $rs = Database::query($sql);
5074
    if ($element_session_id = Database::result($rs, 0, 0)) {
5075
        if ($element_session_id == intval($session_id)) {
5076
            // The element belongs to the session.
5077
            return true;
5078
        }
5079
    }
5080
5081
    return false;
5082
}
5083
5084
/**
5085
 * Replaces "forbidden" characters in a filename string.
5086
 *
5087
 * @param string $filename
5088
 * @param bool   $treat_spaces_as_hyphens
5089
 *
5090
 * @return string
5091
 */
5092
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5093
{
5094
    // Some non-properly encoded file names can cause the whole file to be
5095
    // skipped when uploaded. Avoid this by detecting the encoding and
5096
    // converting to UTF-8, setting the source as ASCII (a reasonably
5097
    // limited characters set) if nothing could be found (BT#
5098
    $encoding = api_detect_encoding($filename);
5099
    if (empty($encoding)) {
5100
        $encoding = 'ASCII';
5101
        if (!api_is_valid_ascii($filename)) {
5102
            // try iconv and try non standard ASCII a.k.a CP437
5103
            // see BT#15022
5104
            if (function_exists('iconv')) {
5105
                $result = iconv('CP437', 'UTF-8', $filename);
5106
                if (api_is_valid_utf8($result)) {
5107
                    $filename = $result;
5108
                    $encoding = 'UTF-8';
5109
                }
5110
            }
5111
        }
5112
    }
5113
5114
    $filename = api_to_system_encoding($filename, $encoding);
5115
5116
    $url = URLify::filter(
5117
        $filename,
5118
        250,
5119
        '',
5120
        true,
5121
        false,
5122
        false
5123
    );
5124
5125
    // Replace multiple dots at the end.
5126
    $regex = "/\.+$/";
5127
5128
    return preg_replace($regex, '', $url);
5129
}
5130
5131
/**
5132
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5133
 *
5134
 * @author Ivan Tcholakov, 28-JUN-2006.
5135
 */
5136
function api_request_uri()
5137
{
5138
    if (!empty($_SERVER['REQUEST_URI'])) {
5139
        return $_SERVER['REQUEST_URI'];
5140
    }
5141
    $uri = $_SERVER['SCRIPT_NAME'];
5142
    if (!empty($_SERVER['QUERY_STRING'])) {
5143
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5144
    }
5145
    $_SERVER['REQUEST_URI'] = $uri;
5146
5147
    return $uri;
5148
}
5149
5150
/**
5151
 * Gets the current access_url id of the Chamilo Platform.
5152
 *
5153
 * @return int access_url_id of the current Chamilo Installation
5154
 *
5155
 * @author Julio Montoya <[email protected]>
5156
 * @throws Exception
5157
 */
5158
function api_get_current_access_url_id(): int
5159
{
5160
    if (false === api_get_multiple_access_url()) {
5161
        return 1;
5162
    }
5163
5164
    static $id;
5165
    if (!empty($id)) {
5166
        return $id;
5167
    }
5168
5169
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5170
    $path = Database::escape_string(api_get_path(WEB_PATH));
5171
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5172
    $result = Database::query($sql);
5173
    if (Database::num_rows($result) > 0) {
5174
        $id = Database::result($result, 0, 0);
5175
        if (false === $id) {
5176
            return -1;
5177
        }
5178
5179
        return (int) $id;
5180
    }
5181
5182
    $id = 1;
5183
5184
    //if the url in WEB_PATH was not found, it can only mean that there is
5185
    // either a configuration problem or the first URL has not been defined yet
5186
    // (by default it is http://localhost/). Thus the more sensible thing we can
5187
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5188
    return 1;
5189
}
5190
5191
/**
5192
 * Gets the registered urls from a given user id.
5193
 *
5194
 * @author Julio Montoya <[email protected]>
5195
 *
5196
 * @param int $user_id
5197
 *
5198
 * @return array
5199
 */
5200
function api_get_access_url_from_user($user_id)
5201
{
5202
    $user_id = (int) $user_id;
5203
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5204
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5205
    $sql = "SELECT access_url_id
5206
            FROM $table_url_rel_user url_rel_user
5207
            INNER JOIN $table_url u
5208
            ON (url_rel_user.access_url_id = u.id)
5209
            WHERE user_id = ".$user_id;
5210
    $result = Database::query($sql);
5211
    $list = [];
5212
    while ($row = Database::fetch_assoc($result)) {
5213
        $list[] = $row['access_url_id'];
5214
    }
5215
5216
    return $list;
5217
}
5218
5219
/**
5220
 * Checks whether the curent user is in a group or not.
5221
 *
5222
 * @param string        The group id - optional (takes it from session if not given)
5223
 * @param string        The course code - optional (no additional check by course if course code is not given)
5224
 *
5225
 * @return bool
5226
 *
5227
 * @author Ivan Tcholakov
5228
 */
5229
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5230
{
5231
    if (!empty($courseCodeParam)) {
5232
        $courseCode = api_get_course_id();
5233
        if (!empty($courseCode)) {
5234
            if ($courseCodeParam != $courseCode) {
5235
                return false;
5236
            }
5237
        } else {
5238
            return false;
5239
        }
5240
    }
5241
5242
    $groupId = api_get_group_id();
5243
5244
    if (isset($groupId) && '' != $groupId) {
5245
        if (!empty($groupIdParam)) {
5246
            return $groupIdParam == $groupId;
5247
        } else {
5248
            return true;
5249
        }
5250
    }
5251
5252
    return false;
5253
}
5254
5255
/**
5256
 * Checks whether a secret key is valid.
5257
 *
5258
 * @param string $original_key_secret - secret key from (webservice) client
5259
 * @param string $security_key        - security key from Chamilo
5260
 *
5261
 * @return bool - true if secret key is valid, false otherwise
5262
 */
5263
function api_is_valid_secret_key($original_key_secret, $security_key)
5264
{
5265
    if (empty($original_key_secret) || empty($security_key)) {
5266
        return false;
5267
    }
5268
5269
    return (string) $original_key_secret === sha1($security_key);
5270
}
5271
5272
/**
5273
 * Checks whether the server's operating system is Windows (TM).
5274
 *
5275
 * @return bool - true if the operating system is Windows, false otherwise
5276
 */
5277
function api_is_windows_os()
5278
{
5279
    if (function_exists('php_uname')) {
5280
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5281
        // We expect that this function will always work for Chamilo 1.8.x.
5282
        $os = php_uname();
5283
    }
5284
    // The following methods are not needed, but let them stay, just in case.
5285
    elseif (isset($_ENV['OS'])) {
5286
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5287
        $os = $_ENV['OS'];
5288
    } elseif (defined('PHP_OS')) {
5289
        // PHP_OS means on which OS PHP was compiled, this is why
5290
        // using PHP_OS is the last choice for detection.
5291
        $os = PHP_OS;
5292
    } else {
5293
        return false;
5294
    }
5295
5296
    return 'win' == strtolower(substr((string) $os, 0, 3));
5297
}
5298
5299
/**
5300
 * This function informs whether the sent request is XMLHttpRequest.
5301
 */
5302
function api_is_xml_http_request()
5303
{
5304
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5305
}
5306
5307
/**
5308
 * Returns a list of Chamilo's tools or
5309
 * checks whether a given identificator is a valid Chamilo's tool.
5310
 *
5311
 * @author Isaac flores paz
5312
 *
5313
 * @param string The tool name to filter
5314
 *
5315
 * @return mixed Filtered string or array
5316
 */
5317
function api_get_tools_lists($my_tool = null)
5318
{
5319
    $tools_list = [
5320
        TOOL_DOCUMENT,
5321
        TOOL_THUMBNAIL,
5322
        TOOL_HOTPOTATOES,
5323
        TOOL_CALENDAR_EVENT,
5324
        TOOL_LINK,
5325
        TOOL_COURSE_DESCRIPTION,
5326
        TOOL_SEARCH,
5327
        TOOL_LEARNPATH,
5328
        TOOL_ANNOUNCEMENT,
5329
        TOOL_FORUM,
5330
        TOOL_THREAD,
5331
        TOOL_POST,
5332
        TOOL_DROPBOX,
5333
        TOOL_QUIZ,
5334
        TOOL_USER,
5335
        TOOL_GROUP,
5336
        TOOL_BLOGS,
5337
        TOOL_CHAT,
5338
        TOOL_STUDENTPUBLICATION,
5339
        TOOL_TRACKING,
5340
        TOOL_HOMEPAGE_LINK,
5341
        TOOL_COURSE_SETTING,
5342
        TOOL_BACKUP,
5343
        TOOL_COPY_COURSE_CONTENT,
5344
        TOOL_RECYCLE_COURSE,
5345
        TOOL_COURSE_HOMEPAGE,
5346
        TOOL_COURSE_RIGHTS_OVERVIEW,
5347
        TOOL_UPLOAD,
5348
        TOOL_COURSE_MAINTENANCE,
5349
        TOOL_SURVEY,
5350
        //TOOL_WIKI,
5351
        TOOL_GLOSSARY,
5352
        TOOL_GRADEBOOK,
5353
        TOOL_NOTEBOOK,
5354
        TOOL_ATTENDANCE,
5355
        TOOL_COURSE_PROGRESS,
5356
    ];
5357
    if (empty($my_tool)) {
5358
        return $tools_list;
5359
    }
5360
5361
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5362
}
5363
5364
/**
5365
 * Checks whether we already approved the last version term and condition.
5366
 *
5367
 * @param int user id
5368
 *
5369
 * @return bool true if we pass false otherwise
5370
 */
5371
function api_check_term_condition($userId)
5372
{
5373
    if ('true' === api_get_setting('allow_terms_conditions')) {
5374
        // Check if exists terms and conditions
5375
        if (0 == LegalManager::count()) {
5376
            return true;
5377
        }
5378
5379
        $extraFieldValue = new ExtraFieldValue('user');
5380
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5381
            $userId,
5382
            'legal_accept'
5383
        );
5384
5385
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5386
            $result = $data['value'];
5387
            $user_conditions = explode(':', $result);
5388
            $version = $user_conditions[0];
5389
            $langId = $user_conditions[1];
5390
            $realVersion = LegalManager::get_last_version($langId);
5391
5392
            return $version >= $realVersion;
5393
        }
5394
5395
        return false;
5396
    }
5397
5398
    return false;
5399
}
5400
5401
/**
5402
 * Gets all information of a tool into course.
5403
 *
5404
 * @param int The tool id
5405
 *
5406
 * @return array
5407
 */
5408
function api_get_tool_information_by_name($name)
5409
{
5410
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5411
    $course_id = api_get_course_int_id();
5412
5413
    $sql = "SELECT id FROM tool
5414
            WHERE title = '".Database::escape_string($name)."' ";
5415
    $rs = Database::query($sql);
5416
    $data = Database::fetch_array($rs);
5417
    if ($data) {
5418
        $tool = $data['id'];
5419
        $sql = "SELECT * FROM $t_tool
5420
                WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
5421
        $rs = Database::query($sql);
5422
5423
        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...
5424
    }
5425
5426
    return [];
5427
}
5428
5429
/**
5430
 * Function used to protect a "global" admin script.
5431
 * The function blocks access when the user has no global platform admin rights.
5432
 * Global admins are the admins that are registered in the main.admin table
5433
 * AND the users who have access to the "principal" portal.
5434
 * That means that there is a record in the main.access_url_rel_user table
5435
 * with his user id and the access_url_id=1.
5436
 *
5437
 * @author Julio Montoya
5438
 *
5439
 * @param int $user_id
5440
 *
5441
 * @return bool
5442
 */
5443
function api_is_global_platform_admin($user_id = null)
5444
{
5445
    $user_id = (int) $user_id;
5446
    if (empty($user_id)) {
5447
        $user_id = api_get_user_id();
5448
    }
5449
    if (api_is_platform_admin_by_id($user_id)) {
5450
        $urlList = api_get_access_url_from_user($user_id);
5451
        // The admin is registered in the first "main" site with access_url_id = 1
5452
        if (in_array(1, $urlList)) {
5453
            return true;
5454
        }
5455
    }
5456
5457
    return false;
5458
}
5459
5460
/**
5461
 * @param int  $admin_id_to_check
5462
 * @param int  $userId
5463
 * @param bool $allow_session_admin
5464
 *
5465
 * @return bool
5466
 */
5467
function api_global_admin_can_edit_admin(
5468
    $admin_id_to_check,
5469
    $userId = 0,
5470
    $allow_session_admin = false
5471
) {
5472
    if (empty($userId)) {
5473
        $userId = api_get_user_id();
5474
    }
5475
5476
    $iam_a_global_admin = api_is_global_platform_admin($userId);
5477
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
5478
5479
    if ($iam_a_global_admin) {
5480
        // Global admin can edit everything
5481
        return true;
5482
    }
5483
5484
    // If i'm a simple admin
5485
    $is_platform_admin = api_is_platform_admin_by_id($userId);
5486
5487
    if ($allow_session_admin && !$is_platform_admin) {
5488
        $user = api_get_user_entity($userId);
5489
        $is_platform_admin = $user->hasRole('ROLE_SESSION_MANAGER');
5490
    }
5491
5492
    if ($is_platform_admin) {
5493
        if ($user_is_global_admin) {
5494
            return false;
5495
        } else {
5496
            return true;
5497
        }
5498
    }
5499
5500
    return false;
5501
}
5502
5503
/**
5504
 * @param int  $admin_id_to_check
5505
 * @param int  $userId
5506
 * @param bool $allow_session_admin
5507
 *
5508
 * @return bool|null
5509
 */
5510
function api_protect_super_admin($admin_id_to_check, $userId = null, $allow_session_admin = false)
5511
{
5512
    if (api_global_admin_can_edit_admin($admin_id_to_check, $userId, $allow_session_admin)) {
5513
        return true;
5514
    } else {
5515
        api_not_allowed();
5516
    }
5517
}
5518
5519
/**
5520
 * Function used to protect a global admin script.
5521
 * The function blocks access when the user has no global platform admin rights.
5522
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
5523
 *
5524
 * @author Julio Montoya
5525
 */
5526
function api_protect_global_admin_script()
5527
{
5528
    if (!api_is_global_platform_admin()) {
5529
        api_not_allowed();
5530
5531
        return false;
5532
    }
5533
5534
    return true;
5535
}
5536
5537
/**
5538
 * Check browser support for specific file types or features
5539
 * This function checks if the user's browser supports a file format or given
5540
 * feature, or returns the current browser and major version when
5541
 * $format=check_browser. Only a limited number of formats and features are
5542
 * checked by this method. Make sure you check its definition first.
5543
 *
5544
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
5545
 *
5546
 * @deprecated
5547
 *
5548
 * @return bool or return text array if $format=check_browser
5549
 *
5550
 * @author Juan Carlos Raña Trabado
5551
 */
5552
function api_browser_support($format = '')
5553
{
5554
    return true;
5555
5556
    $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...
5557
    $current_browser = $browser->getBrowser();
5558
    $a_versiontemp = explode('.', $browser->getVersion());
5559
    $current_majorver = $a_versiontemp[0];
5560
5561
    static $result;
5562
5563
    if (isset($result[$format])) {
5564
        return $result[$format];
5565
    }
5566
5567
    // Native svg support
5568
    if ('svg' == $format) {
5569
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5570
            ('Firefox' == $current_browser && $current_majorver > 1) ||
5571
            ('Safari' == $current_browser && $current_majorver >= 4) ||
5572
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
5573
            ('Opera' == $current_browser && $current_majorver >= 9)
5574
        ) {
5575
            $result[$format] = true;
5576
5577
            return true;
5578
        } else {
5579
            $result[$format] = false;
5580
5581
            return false;
5582
        }
5583
    } elseif ('pdf' == $format) {
5584
        // native pdf support
5585
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
5586
            $result[$format] = true;
5587
5588
            return true;
5589
        } else {
5590
            $result[$format] = false;
5591
5592
            return false;
5593
        }
5594
    } elseif ('tif' == $format || 'tiff' == $format) {
5595
        //native tif support
5596
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5597
            $result[$format] = true;
5598
5599
            return true;
5600
        } else {
5601
            $result[$format] = false;
5602
5603
            return false;
5604
        }
5605
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
5606
        //native ogg, ogv,oga support
5607
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
5608
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
5609
            ('Opera' == $current_browser && $current_majorver >= 9)) {
5610
            $result[$format] = true;
5611
5612
            return true;
5613
        } else {
5614
            $result[$format] = false;
5615
5616
            return false;
5617
        }
5618
    } elseif ('mpg' == $format || 'mpeg' == $format) {
5619
        //native mpg support
5620
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
5621
            $result[$format] = true;
5622
5623
            return true;
5624
        } else {
5625
            $result[$format] = false;
5626
5627
            return false;
5628
        }
5629
    } elseif ('mp4' == $format) {
5630
        //native mp4 support (TODO: Android, iPhone)
5631
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
5632
            $result[$format] = true;
5633
5634
            return true;
5635
        } else {
5636
            $result[$format] = false;
5637
5638
            return false;
5639
        }
5640
    } elseif ('mov' == $format) {
5641
        //native mov support( TODO:check iPhone)
5642
        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...
5643
            $result[$format] = true;
5644
5645
            return true;
5646
        } else {
5647
            $result[$format] = false;
5648
5649
            return false;
5650
        }
5651
    } elseif ('avi' == $format) {
5652
        //native avi support
5653
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5654
            $result[$format] = true;
5655
5656
            return true;
5657
        } else {
5658
            $result[$format] = false;
5659
5660
            return false;
5661
        }
5662
    } elseif ('wmv' == $format) {
5663
        //native wmv support
5664
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5665
            $result[$format] = true;
5666
5667
            return true;
5668
        } else {
5669
            $result[$format] = false;
5670
5671
            return false;
5672
        }
5673
    } elseif ('webm' == $format) {
5674
        //native webm support (TODO:check IE9, Chrome9, Android)
5675
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5676
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5677
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5678
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
5679
            'Android' == $current_browser
5680
        ) {
5681
            $result[$format] = true;
5682
5683
            return true;
5684
        } else {
5685
            $result[$format] = false;
5686
5687
            return false;
5688
        }
5689
    } elseif ('wav' == $format) {
5690
        //native wav support (only some codecs !)
5691
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5692
            ('Safari' == $current_browser && $current_majorver >= 5) ||
5693
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5694
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5695
            ('Chrome' == $current_browser && $current_majorver > 9) ||
5696
            'Android' == $current_browser ||
5697
            'iPhone' == $current_browser
5698
        ) {
5699
            $result[$format] = true;
5700
5701
            return true;
5702
        } else {
5703
            $result[$format] = false;
5704
5705
            return false;
5706
        }
5707
    } elseif ('mid' == $format || 'kar' == $format) {
5708
        //native midi support (TODO:check Android)
5709
        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...
5710
            $result[$format] = true;
5711
5712
            return true;
5713
        } else {
5714
            $result[$format] = false;
5715
5716
            return false;
5717
        }
5718
    } elseif ('wma' == $format) {
5719
        //native wma support
5720
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5721
            $result[$format] = true;
5722
5723
            return true;
5724
        } else {
5725
            $result[$format] = false;
5726
5727
            return false;
5728
        }
5729
    } elseif ('au' == $format) {
5730
        //native au support
5731
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5732
            $result[$format] = true;
5733
5734
            return true;
5735
        } else {
5736
            $result[$format] = false;
5737
5738
            return false;
5739
        }
5740
    } elseif ('mp3' == $format) {
5741
        //native mp3 support (TODO:check Android, iPhone)
5742
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
5743
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
5744
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5745
            'Android' == $current_browser ||
5746
            'iPhone' == $current_browser ||
5747
            'Firefox' == $current_browser
5748
        ) {
5749
            $result[$format] = true;
5750
5751
            return true;
5752
        } else {
5753
            $result[$format] = false;
5754
5755
            return false;
5756
        }
5757
    } elseif ('autocapitalize' == $format) {
5758
        // Help avoiding showing the autocapitalize option if the browser doesn't
5759
        // support it: this attribute is against the HTML5 standard
5760
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
5761
            return true;
5762
        } else {
5763
            return false;
5764
        }
5765
    } elseif ("check_browser" == $format) {
5766
        $array_check_browser = [$current_browser, $current_majorver];
5767
5768
        return $array_check_browser;
5769
    } else {
5770
        $result[$format] = false;
5771
5772
        return false;
5773
    }
5774
}
5775
5776
/**
5777
 * This function checks if exist path and file browscap.ini
5778
 * In order for this to work, your browscap configuration setting in php.ini
5779
 * must point to the correct location of the browscap.ini file on your system
5780
 * http://php.net/manual/en/function.get-browser.php.
5781
 *
5782
 * @return bool
5783
 *
5784
 * @author Juan Carlos Raña Trabado
5785
 */
5786
function api_check_browscap()
5787
{
5788
    $setting = ini_get('browscap');
5789
    if ($setting) {
5790
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
5791
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
5792
            return true;
5793
        }
5794
    }
5795
5796
    return false;
5797
}
5798
5799
/**
5800
 * Returns the <script> HTML tag.
5801
 */
5802
function api_get_js($file)
5803
{
5804
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
5805
}
5806
5807
function api_get_build_js($file)
5808
{
5809
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
5810
}
5811
5812
function api_get_build_css($file, $media = 'screen')
5813
{
5814
    return '<link
5815
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5816
}
5817
5818
/**
5819
 * Returns the <script> HTML tag.
5820
 *
5821
 * @return string
5822
 */
5823
function api_get_asset($file)
5824
{
5825
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
5826
}
5827
5828
/**
5829
 * Returns the <script> HTML tag.
5830
 *
5831
 * @param string $file
5832
 * @param string $media
5833
 *
5834
 * @return string
5835
 */
5836
function api_get_css_asset($file, $media = 'screen')
5837
{
5838
    return '<link
5839
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"
5840
        rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5841
}
5842
5843
/**
5844
 * Returns the <link> HTML tag.
5845
 *
5846
 * @param string $file
5847
 * @param string $media
5848
 */
5849
function api_get_css($file, $media = 'screen')
5850
{
5851
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5852
}
5853
5854
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false, $returnFileLocation = false)
5855
{
5856
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
5857
5858
    if ($returnOnlyPath) {
5859
        if ($returnFileLocation) {
5860
            return api_get_path(SYS_PUBLIC_PATH).'build/css/bootstrap.css';
5861
        }
5862
5863
        return $url;
5864
    }
5865
5866
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
5867
}
5868
5869
/**
5870
 * Returns the js header to include the jquery library.
5871
 */
5872
function api_get_jquery_js()
5873
{
5874
    return api_get_asset('jquery/jquery.min.js');
5875
}
5876
5877
/**
5878
 * Returns the jquery path.
5879
 *
5880
 * @return string
5881
 */
5882
function api_get_jquery_web_path()
5883
{
5884
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
5885
}
5886
5887
/**
5888
 * @return string
5889
 */
5890
function api_get_jquery_ui_js_web_path()
5891
{
5892
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
5893
}
5894
5895
/**
5896
 * @return string
5897
 */
5898
function api_get_jquery_ui_css_web_path()
5899
{
5900
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
5901
}
5902
5903
/**
5904
 * Returns the jquery-ui library js headers.
5905
 *
5906
 * @return string html tags
5907
 */
5908
function api_get_jquery_ui_js()
5909
{
5910
    $libraries = [];
5911
5912
    return api_get_jquery_libraries_js($libraries);
5913
}
5914
5915
function api_get_jqgrid_js()
5916
{
5917
    return api_get_build_css('legacy_free-jqgrid.css').PHP_EOL
5918
        .api_get_build_js('legacy_free-jqgrid.js');
5919
}
5920
5921
/**
5922
 * Returns the jquery library js and css headers.
5923
 *
5924
 * @param   array   list of jquery libraries supported jquery-ui
5925
 * @param   bool    add the jquery library
5926
 *
5927
 * @return string html tags
5928
 */
5929
function api_get_jquery_libraries_js($libraries)
5930
{
5931
    $js = '';
5932
5933
    //Document multiple upload funcionality
5934
    if (in_array('jquery-uploadzs', $libraries)) {
5935
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
5936
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
5937
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
5938
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
5939
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
5940
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
5941
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
5942
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
5943
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
5944
5945
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
5946
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
5947
    }
5948
5949
    // jquery datepicker
5950
    if (in_array('datepicker', $libraries)) {
5951
        $languaje = 'en-GB';
5952
        $platform_isocode = strtolower(api_get_language_isocode());
5953
5954
        $datapicker_langs = [
5955
            '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',
5956
        ];
5957
        if (in_array($platform_isocode, $datapicker_langs)) {
5958
            $languaje = $platform_isocode;
5959
        }
5960
5961
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
5962
        $script = '<script>
5963
        $(function(){
5964
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
5965
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
5966
        });
5967
        </script>
5968
        ';
5969
        $js .= $script;
5970
    }
5971
5972
    return $js;
5973
}
5974
5975
/**
5976
 * Returns the URL to the course or session, removing the complexity of the URL
5977
 * building piece by piece.
5978
 *
5979
 * This function relies on api_get_course_info()
5980
 *
5981
 * @param int $courseId  The course code - optional (takes it from context if not given)
5982
 * @param int $sessionId The session ID  - optional (takes it from context if not given)
5983
 * @param int $groupId   The group ID - optional (takes it from context if not given)
5984
 *
5985
 * @return string The URL to a course, a session, or empty string if nothing works
5986
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
5987
 *
5988
 * @author  Julio Montoya
5989
 */
5990
function api_get_course_url($courseId = null, $sessionId = null, $groupId = null)
5991
{
5992
    $url = '';
5993
    // If courseCode not set, get context or []
5994
    if (empty($courseId)) {
5995
        $courseId = api_get_course_int_id();
5996
    }
5997
5998
    // If sessionId not set, get context or 0
5999
    if (empty($sessionId)) {
6000
        $sessionId = api_get_session_id();
6001
    }
6002
6003
    // If groupId not set, get context or 0
6004
    if (empty($groupId)) {
6005
        $groupId = api_get_group_id();
6006
    }
6007
6008
    // Build the URL
6009
    if (!empty($courseId)) {
6010
        $webCourseHome = '/course/'.$courseId.'/home';
6011
        // directory not empty, so we do have a course
6012
        $url = $webCourseHome.'?sid='.$sessionId.'&gid='.$groupId;
6013
    } else {
6014
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
6015
            // if the course was unset and the session was set, send directly to the session
6016
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6017
        }
6018
    }
6019
6020
    // if not valid combination was found, return an empty string
6021
    return $url;
6022
}
6023
6024
/**
6025
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6026
 */
6027
function api_get_multiple_access_url(): bool
6028
{
6029
    global $_configuration;
6030
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6031
        return true;
6032
    }
6033
6034
    return false;
6035
}
6036
6037
function api_is_multiple_url_enabled(): bool
6038
{
6039
    return api_get_multiple_access_url();
6040
}
6041
6042
/**
6043
 * Returns a md5 unique id.
6044
 *
6045
 * @todo add more parameters
6046
 */
6047
function api_get_unique_id()
6048
{
6049
    return md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6050
}
6051
6052
/**
6053
 * @param int Course id
6054
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6055
 * @param int the item id (tool id, exercise id, lp id)
6056
 *
6057
 * @return bool
6058
 */
6059
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6060
{
6061
    if (api_is_platform_admin()) {
6062
        return false;
6063
    }
6064
    if ('true' === api_get_setting('gradebook_locking_enabled')) {
6065
        if (empty($course_code)) {
6066
            $course_code = api_get_course_id();
6067
        }
6068
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6069
        $item_id = (int) $item_id;
6070
        $link_type = (int) $link_type;
6071
        $course_code = Database::escape_string($course_code);
6072
        $sql = "SELECT locked FROM $table
6073
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6074
        $result = Database::query($sql);
6075
        if (Database::num_rows($result)) {
6076
            return true;
6077
        }
6078
    }
6079
6080
    return false;
6081
}
6082
6083
/**
6084
 * Blocks a page if the item was added in a gradebook.
6085
 *
6086
 * @param int       exercise id, work id, thread id,
6087
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6088
 * see gradebook/lib/be/linkfactory
6089
 * @param string    course code
6090
 *
6091
 * @return false|null
6092
 */
6093
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6094
{
6095
    if (api_is_platform_admin()) {
6096
        return false;
6097
    }
6098
6099
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6100
        $message = Display::return_message(
6101
            get_lang(
6102
                '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.'
6103
            ),
6104
            'warning'
6105
        );
6106
        api_not_allowed(true, $message);
6107
    }
6108
}
6109
6110
/**
6111
 * Checks the PHP version installed is enough to run Chamilo.
6112
 *
6113
 * @param string Include path (used to load the error page)
6114
 */
6115
function api_check_php_version()
6116
{
6117
    if (!function_exists('version_compare') ||
6118
        version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')
6119
    ) {
6120
        throw new Exception('Wrong PHP version');
6121
    }
6122
}
6123
6124
/**
6125
 * Checks whether the Archive directory is present and writeable. If not,
6126
 * prints a warning message.
6127
 */
6128
function api_check_archive_dir()
6129
{
6130
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6131
        $message = Display::return_message(
6132
            get_lang(
6133
                'The var/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'
6134
            ),
6135
            'warning'
6136
        );
6137
        api_not_allowed(true, $message);
6138
    }
6139
}
6140
6141
/**
6142
 * Returns an array of global configuration settings which should be ignored
6143
 * when printing the configuration settings screens.
6144
 *
6145
 * @return array Array of strings, each identifying one of the excluded settings
6146
 */
6147
function api_get_locked_settings()
6148
{
6149
    return [
6150
        'permanently_remove_deleted_files',
6151
        'account_valid_duration',
6152
        'service_ppt2lp',
6153
        'wcag_anysurfer_public_pages',
6154
        'upload_extensions_list_type',
6155
        'upload_extensions_blacklist',
6156
        'upload_extensions_whitelist',
6157
        'upload_extensions_skip',
6158
        'upload_extensions_replace_by',
6159
        'hide_dltt_markup',
6160
        'split_users_upload_directory',
6161
        'permissions_for_new_directories',
6162
        'permissions_for_new_files',
6163
        'platform_charset',
6164
        'ldap_description',
6165
        'cas_activate',
6166
        'cas_server',
6167
        'cas_server_uri',
6168
        'cas_port',
6169
        'cas_protocol',
6170
        'cas_add_user_activate',
6171
        'update_user_info_cas_with_ldap',
6172
        'languagePriority1',
6173
        'languagePriority2',
6174
        'languagePriority3',
6175
        'languagePriority4',
6176
        'login_is_email',
6177
        'chamilo_database_version',
6178
    ];
6179
}
6180
6181
/**
6182
 * Guess the real ip for register in the database, even in reverse proxy cases.
6183
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6184
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6185
 * Note: the result of this function is not SQL-safe. Please escape it before
6186
 * inserting in a database.
6187
 *
6188
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6189
 *
6190
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6191
 *
6192
 * @version CEV CHANGE 24APR2012
6193
 * @throws RuntimeException
6194
 */
6195
function api_get_real_ip(): string
6196
{
6197
    if ('cli' === PHP_SAPI) {
6198
        $ip = '127.0.0.1';
6199
    } else {
6200
        $ip = trim($_SERVER['REMOTE_ADDR']);
6201
        if (empty($ip)) {
6202
            throw new RuntimeException("Unable to retrieve remote IP address.");
6203
        }
6204
    }
6205
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6206
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6207
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6208
        } else {
6209
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6210
        }
6211
        $ip = trim($ip1);
6212
    }
6213
6214
    return $ip;
6215
}
6216
6217
/**
6218
 * Checks whether an IP is included inside an IP range.
6219
 *
6220
 * @param string IP address
6221
 * @param string IP range
6222
 * @param string $ip
6223
 *
6224
 * @return bool True if IP is in the range, false otherwise
6225
 *
6226
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6227
 * @author Yannick Warnier for improvements and managment of multiple ranges
6228
 *
6229
 * @todo check for IPv6 support
6230
 */
6231
function api_check_ip_in_range($ip, $range)
6232
{
6233
    if (empty($ip) or empty($range)) {
6234
        return false;
6235
    }
6236
    $ip_ip = ip2long($ip);
6237
    // divide range param into array of elements
6238
    if (false !== strpos($range, ',')) {
6239
        $ranges = explode(',', $range);
6240
    } else {
6241
        $ranges = [$range];
6242
    }
6243
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6244
        $range = trim($range);
6245
        if (empty($range)) {
6246
            continue;
6247
        }
6248
        if (false === strpos($range, '/')) {
6249
            if (0 === strcmp($ip, $range)) {
6250
                return true; // there is a direct IP match, return OK
6251
            }
6252
            continue; //otherwise, get to the next range
6253
        }
6254
        // the range contains a "/", so analyse completely
6255
        [$net, $mask] = explode("/", $range);
6256
6257
        $ip_net = ip2long($net);
6258
        // mask binary magic
6259
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6260
6261
        $ip_ip_net = $ip_ip & $ip_mask;
6262
        if ($ip_ip_net == $ip_net) {
6263
            return true;
6264
        }
6265
    }
6266
6267
    return false;
6268
}
6269
6270
function api_check_user_access_to_legal($courseInfo)
6271
{
6272
    if (empty($courseInfo)) {
6273
        return false;
6274
    }
6275
6276
    $visibility = (int) $courseInfo['visibility'];
6277
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6278
6279
    return
6280
        in_array($visibility, $visibilityList) ||
6281
        api_is_drh() ||
6282
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
6283
}
6284
6285
/**
6286
 * Checks if the global chat is enabled or not.
6287
 *
6288
 * @return bool
6289
 */
6290
function api_is_global_chat_enabled()
6291
{
6292
    return
6293
        !api_is_anonymous() &&
6294
        'true' === api_get_setting('allow_global_chat') &&
6295
        'true' === api_get_setting('allow_social_tool');
6296
}
6297
6298
/**
6299
 * @param int   $item_id
6300
 * @param int   $tool_id
6301
 * @param int   $group_id   id
6302
 * @param array $courseInfo
6303
 * @param int   $sessionId
6304
 * @param int   $userId
6305
 *
6306
 * @deprecated
6307
 */
6308
function api_set_default_visibility(
6309
    $item_id,
6310
    $tool_id,
6311
    $group_id = 0,
6312
    $courseInfo = [],
6313
    $sessionId = 0,
6314
    $userId = 0
6315
) {
6316
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6317
    $courseId = $courseInfo['real_id'];
6318
    $courseCode = $courseInfo['code'];
6319
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6320
    $userId = empty($userId) ? api_get_user_id() : $userId;
6321
6322
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6323
    if (is_null($group_id)) {
6324
        $group_id = 0;
6325
    } else {
6326
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6327
    }
6328
6329
    $groupInfo = [];
6330
    if (!empty($group_id)) {
6331
        $groupInfo = GroupManager::get_group_properties($group_id);
6332
    }
6333
    $original_tool_id = $tool_id;
6334
6335
    switch ($tool_id) {
6336
        case TOOL_LINK:
6337
        case TOOL_LINK_CATEGORY:
6338
            $tool_id = 'links';
6339
            break;
6340
        case TOOL_DOCUMENT:
6341
            $tool_id = 'documents';
6342
            break;
6343
        case TOOL_LEARNPATH:
6344
            $tool_id = 'learning';
6345
            break;
6346
        case TOOL_ANNOUNCEMENT:
6347
            $tool_id = 'announcements';
6348
            break;
6349
        case TOOL_FORUM:
6350
        case TOOL_FORUM_CATEGORY:
6351
        case TOOL_FORUM_THREAD:
6352
            $tool_id = 'forums';
6353
            break;
6354
        case TOOL_QUIZ:
6355
            $tool_id = 'quiz';
6356
            break;
6357
    }
6358
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6359
6360
    if (isset($setting[$tool_id])) {
6361
        $visibility = 'invisible';
6362
        if ('true' === $setting[$tool_id]) {
6363
            $visibility = 'visible';
6364
        }
6365
6366
        // Read the portal and course default visibility
6367
        if ('documents' === $tool_id) {
6368
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6369
        }
6370
6371
        // Fixes default visibility for tests
6372
        switch ($original_tool_id) {
6373
            case TOOL_QUIZ:
6374
                if (empty($sessionId)) {
6375
                    $objExerciseTmp = new Exercise($courseId);
6376
                    $objExerciseTmp->read($item_id);
6377
                    if ('visible' === $visibility) {
6378
                        $objExerciseTmp->enable();
6379
                        $objExerciseTmp->save();
6380
                    } else {
6381
                        $objExerciseTmp->disable();
6382
                        $objExerciseTmp->save();
6383
                    }
6384
                }
6385
                break;
6386
        }
6387
    }
6388
}
6389
6390
function api_get_roles()
6391
{
6392
    $hierarchy = Container::$container->getParameter('security.role_hierarchy.roles');
0 ignored issues
show
Bug introduced by
The method getParameter() does not exist on null. ( Ignorable by Annotation )

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

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

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

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

Loading history...
6393
    $roles = [];
6394
    array_walk_recursive($hierarchy, function ($role) use (&$roles) {
6395
        $roles[$role] = $role;
6396
    });
6397
6398
    return $roles;
6399
}
6400
6401
function api_get_user_roles(): array
6402
{
6403
    $roles = [
6404
        'ROLE_TEACHER',
6405
        'ROLE_STUDENT',
6406
        'ROLE_RRHH',
6407
        'ROLE_SESSION_MANAGER',
6408
        'ROLE_STUDENT_BOSS',
6409
        'ROLE_INVITEE',
6410
        'ROLE_USER',
6411
    ];
6412
6413
    return array_combine($roles, $roles);
6414
}
6415
6416
/**
6417
 * @param string $file
6418
 *
6419
 * @return string
6420
 */
6421
function api_get_js_simple($file)
6422
{
6423
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
6424
}
6425
6426
/**
6427
 * Modify default memory_limit and max_execution_time limits
6428
 * Needed when processing long tasks.
6429
 */
6430
function api_set_more_memory_and_time_limits()
6431
{
6432
    if (function_exists('ini_set')) {
6433
        api_set_memory_limit('256M');
6434
        ini_set('max_execution_time', 1800);
6435
    }
6436
}
6437
6438
/**
6439
 * Tries to set memory limit, if authorized and new limit is higher than current.
6440
 *
6441
 * @param string $mem New memory limit
6442
 *
6443
 * @return bool True on success, false on failure or current is higher than suggested
6444
 * @assert (null) === false
6445
 * @assert (-1) === false
6446
 * @assert (0) === true
6447
 * @assert ('1G') === true
6448
 */
6449
function api_set_memory_limit($mem)
6450
{
6451
    //if ini_set() not available, this function is useless
6452
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
6453
        return false;
6454
    }
6455
6456
    $memory_limit = ini_get('memory_limit');
6457
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
6458
        ini_set('memory_limit', $mem);
6459
6460
        return true;
6461
    }
6462
6463
    return false;
6464
}
6465
6466
/**
6467
 * Gets memory limit in bytes.
6468
 *
6469
 * @param string The memory size (128M, 1G, 1000K, etc)
6470
 *
6471
 * @return int
6472
 * @assert (null) === false
6473
 * @assert ('1t')  === 1099511627776
6474
 * @assert ('1g')  === 1073741824
6475
 * @assert ('1m')  === 1048576
6476
 * @assert ('100k') === 102400
6477
 */
6478
function api_get_bytes_memory_limit($mem)
6479
{
6480
    $size = strtolower(substr($mem, -1));
6481
6482
    switch ($size) {
6483
        case 't':
6484
            $mem = (int) substr($mem, -1) * 1024 * 1024 * 1024 * 1024;
6485
            break;
6486
        case 'g':
6487
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024 * 1024;
6488
            break;
6489
        case 'm':
6490
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024;
6491
            break;
6492
        case 'k':
6493
            $mem = (int) substr($mem, 0, -1) * 1024;
6494
            break;
6495
        default:
6496
            // we assume it's integer only
6497
            $mem = (int) $mem;
6498
            break;
6499
    }
6500
6501
    return $mem;
6502
}
6503
6504
/**
6505
 * Finds all the information about a user from username instead of user id.
6506
 *
6507
 * @param string $officialCode
6508
 *
6509
 * @return array $user_info user_id, lastname, firstname, username, email, ...
6510
 *
6511
 * @author Yannick Warnier <[email protected]>
6512
 */
6513
function api_get_user_info_from_official_code($officialCode)
6514
{
6515
    if (empty($officialCode)) {
6516
        return false;
6517
    }
6518
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
6519
            WHERE official_code ='".Database::escape_string($officialCode)."'";
6520
    $result = Database::query($sql);
6521
    if (Database::num_rows($result) > 0) {
6522
        $result_array = Database::fetch_array($result);
6523
6524
        return _api_format_user($result_array);
6525
    }
6526
6527
    return false;
6528
}
6529
6530
/**
6531
 * @param string $usernameInputId
6532
 * @param string $passwordInputId
6533
 *
6534
 * @return string|null
6535
 */
6536
function api_get_password_checker_js($usernameInputId, $passwordInputId)
6537
{
6538
    $checkPass = api_get_setting('allow_strength_pass_checker');
6539
    $useStrengthPassChecker = 'true' === $checkPass;
6540
6541
    if (false === $useStrengthPassChecker) {
6542
        return null;
6543
    }
6544
6545
    $minRequirements = Security::getPasswordRequirements()['min'];
6546
6547
    $options = [
6548
        'rules' => [],
6549
    ];
6550
6551
    if ($minRequirements['length'] > 0) {
6552
        $options['rules'][] = [
6553
            'minChar' => $minRequirements['length'],
6554
            'pattern' => '.',
6555
            'helpText' => sprintf(
6556
                get_lang('Minimum %s characters in total'),
6557
                $minRequirements['length']
6558
            ),
6559
        ];
6560
    }
6561
6562
    if ($minRequirements['lowercase'] > 0) {
6563
        $options['rules'][] = [
6564
            'minChar' => $minRequirements['lowercase'],
6565
            'pattern' => '[a-z]',
6566
            'helpText' => sprintf(
6567
                get_lang('Minimum %s lowercase characters'),
6568
                $minRequirements['lowercase']
6569
            ),
6570
        ];
6571
    }
6572
6573
    if ($minRequirements['uppercase'] > 0) {
6574
        $options['rules'][] = [
6575
            'minChar' => $minRequirements['uppercase'],
6576
            'pattern' => '[A-Z]',
6577
            'helpText' => sprintf(
6578
                get_lang('Minimum %s uppercase characters'),
6579
                $minRequirements['uppercase']
6580
            ),
6581
        ];
6582
    }
6583
6584
    if ($minRequirements['numeric'] > 0) {
6585
        $options['rules'][] = [
6586
            'minChar' => $minRequirements['numeric'],
6587
            'pattern' => '[0-9]',
6588
            'helpText' => sprintf(
6589
                get_lang('Minimum %s numerical (0-9) characters'),
6590
                $minRequirements['numeric']
6591
            ),
6592
        ];
6593
    }
6594
6595
    if ($minRequirements['specials'] > 0) {
6596
        $options['rules'][] = [
6597
            'minChar' => $minRequirements['specials'],
6598
            'pattern' => '[!"#$%&\'()*+,\-./\\\:;<=>?@[\\]^_`{|}~]',
6599
            'helpText' => sprintf(
6600
                get_lang('Minimum %s special characters'),
6601
                $minRequirements['specials']
6602
            ),
6603
        ];
6604
    }
6605
6606
    $js = api_get_js('password-checker/password-checker.js');
6607
    $js .= "<script>
6608
    $(function() {
6609
        $('".$passwordInputId."').passwordChecker(".json_encode($options).");
6610
    });
6611
    </script>";
6612
6613
    return $js;
6614
}
6615
6616
/**
6617
 * create an user extra field called 'captcha_blocked_until_date'.
6618
 *
6619
 * @param string $username
6620
 *
6621
 * @return bool
6622
 */
6623
function api_block_account_captcha($username)
6624
{
6625
    $userInfo = api_get_user_info_from_username($username);
6626
    if (empty($userInfo)) {
6627
        return false;
6628
    }
6629
    $minutesToBlock = api_get_setting('captcha_time_to_block');
6630
    $time = time() + $minutesToBlock * 60;
6631
    UserManager::update_extra_field_value(
6632
        $userInfo['user_id'],
6633
        'captcha_blocked_until_date',
6634
        api_get_utc_datetime($time)
6635
    );
6636
6637
    return true;
6638
}
6639
6640
/**
6641
 * @param string $username
6642
 *
6643
 * @return bool
6644
 */
6645
function api_clean_account_captcha($username)
6646
{
6647
    $userInfo = api_get_user_info_from_username($username);
6648
    if (empty($userInfo)) {
6649
        return false;
6650
    }
6651
    Session::erase('loginFailedCount');
6652
    UserManager::update_extra_field_value(
6653
        $userInfo['user_id'],
6654
        'captcha_blocked_until_date',
6655
        null
6656
    );
6657
6658
    return true;
6659
}
6660
6661
/**
6662
 * @param string $username
6663
 *
6664
 * @return bool
6665
 */
6666
function api_get_user_blocked_by_captcha($username)
6667
{
6668
    $userInfo = api_get_user_info_from_username($username);
6669
    if (empty($userInfo)) {
6670
        return false;
6671
    }
6672
    $data = UserManager::get_extra_user_data_by_field(
6673
        $userInfo['user_id'],
6674
        'captcha_blocked_until_date'
6675
    );
6676
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
6677
        return $data['captcha_blocked_until_date'];
6678
    }
6679
6680
    return false;
6681
}
6682
6683
/**
6684
 * If true, the drh can access all content (courses, users) inside a session.
6685
 *
6686
 * @return bool
6687
 */
6688
function api_drh_can_access_all_session_content()
6689
{
6690
    return 'true' === api_get_setting('drh_can_access_all_session_content');
6691
}
6692
6693
/**
6694
 * Checks if user can login as another user.
6695
 *
6696
 * @param int $loginAsUserId the user id to log in
6697
 * @param int $userId        my user id
6698
 *
6699
 * @return bool
6700
 */
6701
function api_can_login_as($loginAsUserId, $userId = null)
6702
{
6703
    $loginAsUserId = (int) $loginAsUserId;
6704
6705
    if (empty($loginAsUserId)) {
6706
        return false;
6707
    }
6708
6709
    if (empty($userId)) {
6710
        $userId = api_get_user_id();
6711
    }
6712
6713
    if ($loginAsUserId == $userId) {
6714
        return false;
6715
    }
6716
6717
    // Check if the user to login is an admin
6718
    if (api_is_platform_admin_by_id($loginAsUserId)) {
6719
        // Only super admins can login to admin accounts
6720
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
6721
            return false;
6722
        }
6723
    }
6724
6725
    $userInfo = api_get_user_info($loginAsUserId);
6726
6727
    $isDrh = function () use ($loginAsUserId) {
6728
        if (api_is_drh()) {
6729
            if (api_drh_can_access_all_session_content()) {
6730
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
6731
                    'drh_all',
6732
                    api_get_user_id()
6733
                );
6734
                $userList = [];
6735
                if (is_array($users)) {
6736
                    foreach ($users as $user) {
6737
                        $userList[] = $user['id'];
6738
                    }
6739
                }
6740
                if (in_array($loginAsUserId, $userList)) {
6741
                    return true;
6742
                }
6743
            } else {
6744
                if (api_is_drh() &&
6745
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
6746
                ) {
6747
                    return true;
6748
                }
6749
            }
6750
        }
6751
6752
        return false;
6753
    };
6754
6755
    $loginAsStatusForSessionAdmins = [STUDENT];
6756
6757
    if ('true' === api_get_setting('session.allow_session_admin_login_as_teacher')) {
6758
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
6759
    }
6760
6761
    return api_is_platform_admin() ||
6762
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
6763
        $isDrh();
6764
}
6765
6766
/**
6767
 * Return true on https install.
6768
 *
6769
 * @return bool
6770
 */
6771
function api_is_https()
6772
{
6773
    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...
6774
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
6775
    ) {
6776
        $isSecured = true;
6777
    } else {
6778
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
6779
            $isSecured = true;
6780
        } else {
6781
            $isSecured = false;
6782
            // last chance
6783
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
6784
                $isSecured = true;
6785
            }
6786
        }
6787
    }
6788
6789
    return $isSecured;
6790
}
6791
6792
/**
6793
 * Return protocol (http or https).
6794
 *
6795
 * @return string
6796
 */
6797
function api_get_protocol()
6798
{
6799
    return api_is_https() ? 'https' : 'http';
6800
}
6801
6802
/**
6803
 * Get origin.
6804
 *
6805
 * @param string
6806
 *
6807
 * @return string
6808
 */
6809
function api_get_origin()
6810
{
6811
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
6812
}
6813
6814
/**
6815
 * Warns an user that the portal reach certain limit.
6816
 *
6817
 * @param string $limitName
6818
 */
6819
function api_warn_hosting_contact($limitName)
6820
{
6821
    $hostingParams = api_get_configuration_value(1);
6822
    $email = null;
6823
6824
    if (!empty($hostingParams)) {
6825
        if (isset($hostingParams['hosting_contact_mail'])) {
6826
            $email = $hostingParams['hosting_contact_mail'];
6827
        }
6828
    }
6829
6830
    if (!empty($email)) {
6831
        $subject = get_lang('Hosting warning reached');
6832
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
6833
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
6834
        if (isset($hostingParams[$limitName])) {
6835
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
6836
        }
6837
        api_mail_html(null, $email, $subject, $body);
6838
    }
6839
}
6840
6841
/**
6842
 * Gets value of a variable from config/configuration.php
6843
 * Variables that are not set in the configuration.php file but set elsewhere:
6844
 * - virtual_css_theme_folder (vchamilo plugin)
6845
 * - access_url (global.inc.php)
6846
 * - apc/apc_prefix (global.inc.php).
6847
 *
6848
 * @param string $variable
6849
 *
6850
 * @return bool|mixed
6851
 */
6852
function api_get_configuration_value($variable)
6853
{
6854
    global $_configuration;
6855
    // Check the current url id, id = 1 by default
6856
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
6857
6858
    $variable = trim($variable);
6859
6860
    // Check if variable exists
6861
    if (isset($_configuration[$variable])) {
6862
        if (is_array($_configuration[$variable])) {
6863
            // Check if it exists for the sub portal
6864
            if (array_key_exists($urlId, $_configuration[$variable])) {
6865
                return $_configuration[$variable][$urlId];
6866
            } else {
6867
                // Try to found element with id = 1 (master portal)
6868
                if (array_key_exists(1, $_configuration[$variable])) {
6869
                    return $_configuration[$variable][1];
6870
                }
6871
            }
6872
        }
6873
6874
        return $_configuration[$variable];
6875
    }
6876
6877
    return false;
6878
}
6879
6880
/**
6881
 * Retreives and returns a value in a hierarchical configuration array
6882
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
6883
 *
6884
 * @param string $path      the successive array keys, separated by the separator
6885
 * @param mixed  $default   value to be returned if not found, null by default
6886
 * @param string $separator '/' by default
6887
 * @param array  $array     the active configuration array by default
6888
 *
6889
 * @return mixed the found value or $default
6890
 */
6891
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
6892
{
6893
    $pos = strpos($path, $separator);
6894
    if (false === $pos) {
6895
        if (is_null($array)) {
6896
            return api_get_configuration_value($path);
6897
        }
6898
        if (is_array($array) && array_key_exists($path, $array)) {
6899
            return $array[$path];
6900
        }
6901
6902
        return $default;
6903
    }
6904
    $key = substr($path, 0, $pos);
6905
    if (is_null($array)) {
6906
        $newArray = api_get_configuration_value($key);
6907
    } elseif (is_array($array) && array_key_exists($key, $array)) {
6908
        $newArray = $array[$key];
6909
    } else {
6910
        return $default;
6911
    }
6912
    if (is_array($newArray)) {
6913
        $newPath = substr($path, $pos + 1);
6914
6915
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
6916
    }
6917
6918
    return $default;
6919
}
6920
6921
/**
6922
 * Retrieves and returns a value in a hierarchical configuration array
6923
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
6924
 *
6925
 * @param array  $array     the recursive array that contains the value to be returned (or not)
6926
 * @param string $path      the successive array keys, separated by the separator
6927
 * @param mixed  $default   the value to be returned if not found
6928
 * @param string $separator the separator substring
6929
 *
6930
 * @return mixed the found value or $default
6931
 */
6932
function api_array_sub_value($array, $path, $default = null, $separator = '/')
6933
{
6934
    $pos = strpos($path, $separator);
6935
    if (false === $pos) {
6936
        if (is_array($array) && array_key_exists($path, $array)) {
6937
            return $array[$path];
6938
        }
6939
6940
        return $default;
6941
    }
6942
    $key = substr($path, 0, $pos);
6943
    if (is_array($array) && array_key_exists($key, $array)) {
6944
        $newArray = $array[$key];
6945
    } else {
6946
        return $default;
6947
    }
6948
    if (is_array($newArray)) {
6949
        $newPath = substr($path, $pos + 1);
6950
6951
        return api_array_sub_value($newArray, $newPath, $default);
6952
    }
6953
6954
    return $default;
6955
}
6956
6957
/**
6958
 * Returns supported image extensions in the portal.
6959
 *
6960
 * @param bool $supportVectors Whether vector images should also be accepted or not
6961
 *
6962
 * @return array Supported image extensions in the portal
6963
 */
6964
function api_get_supported_image_extensions($supportVectors = true)
6965
{
6966
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
6967
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
6968
    if ($supportVectors) {
6969
        array_push($supportedImageExtensions, 'svg');
6970
    }
6971
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
6972
        array_push($supportedImageExtensions, 'webp');
6973
    }
6974
6975
    return $supportedImageExtensions;
6976
}
6977
6978
/**
6979
 * This setting changes the registration status for the campus.
6980
 *
6981
 * @author Patrick Cool <[email protected]>, Ghent University
6982
 *
6983
 * @version August 2006
6984
 *
6985
 * @param bool $listCampus Whether we authorize
6986
 *
6987
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
6988
 */
6989
function api_register_campus($listCampus = true)
6990
{
6991
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6992
6993
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
6994
    Database::query($sql);
6995
6996
    if (!$listCampus) {
6997
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
6998
        Database::query($sql);
6999
    }
7000
}
7001
7002
/**
7003
 * Check whether the user type should be exclude.
7004
 * Such as invited or anonymous users.
7005
 *
7006
 * @param bool $checkDB Optional. Whether check the user status
7007
 * @param int  $userId  Options. The user id
7008
 *
7009
 * @return bool
7010
 */
7011
function api_is_excluded_user_type($checkDB = false, $userId = 0)
7012
{
7013
    if ($checkDB) {
7014
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
7015
7016
        if (0 == $userId) {
7017
            return true;
7018
        }
7019
7020
        $userInfo = api_get_user_info($userId);
7021
7022
        switch ($userInfo['status']) {
7023
            case INVITEE:
7024
            case ANONYMOUS:
7025
                return true;
7026
            default:
7027
                return false;
7028
        }
7029
    }
7030
7031
    $isInvited = api_is_invitee();
7032
    $isAnonymous = api_is_anonymous();
7033
7034
    if ($isInvited || $isAnonymous) {
7035
        return true;
7036
    }
7037
7038
    return false;
7039
}
7040
7041
/**
7042
 * Get the user status to ignore in reports.
7043
 *
7044
 * @param string $format Optional. The result type (array or string)
7045
 *
7046
 * @return array|string
7047
 */
7048
function api_get_users_status_ignored_in_reports($format = 'array')
7049
{
7050
    $excludedTypes = [
7051
        INVITEE,
7052
        ANONYMOUS,
7053
    ];
7054
7055
    if ('string' == $format) {
7056
        return implode(', ', $excludedTypes);
7057
    }
7058
7059
    return $excludedTypes;
7060
}
7061
7062
/**
7063
 * Set the Site Use Cookie Warning for 1 year.
7064
 */
7065
function api_set_site_use_cookie_warning_cookie()
7066
{
7067
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
7068
}
7069
7070
/**
7071
 * Return true if the Site Use Cookie Warning Cookie warning exists.
7072
 *
7073
 * @return bool
7074
 */
7075
function api_site_use_cookie_warning_cookie_exist()
7076
{
7077
    return isset($_COOKIE['ChamiloUsesCookies']);
7078
}
7079
7080
/**
7081
 * Given a number of seconds, format the time to show hours, minutes and seconds.
7082
 *
7083
 * @param int    $time         The time in seconds
7084
 * @param string $originFormat Optional. PHP o JS
7085
 *
7086
 * @return string (00h00'00")
7087
 */
7088
function api_format_time($time, $originFormat = 'php')
7089
{
7090
    $h = get_lang('h');
7091
    $hours = $time / 3600;
7092
    $mins = ($time % 3600) / 60;
7093
    $secs = ($time % 60);
7094
7095
    if ($time < 0) {
7096
        $hours = 0;
7097
        $mins = 0;
7098
        $secs = 0;
7099
    }
7100
7101
    if ('js' === $originFormat) {
7102
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
7103
    } else {
7104
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
7105
    }
7106
7107
    return $formattedTime;
7108
}
7109
7110
function api_set_noreply_and_from_address_to_mailer(
7111
    TemplatedEmail $email,
7112
    array $sender,
7113
    array $replyToAddress = []
7114
): void {
7115
    $noReplyAddress = api_get_setting('noreply_email_address');
7116
    $avoidReplyToAddress = false;
7117
7118
    if (!empty($noReplyAddress)) {
7119
        // $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
7120
    }
7121
7122
    // Default values
7123
    $notification = new Notification();
7124
    $defaultSenderName = $notification->getDefaultPlatformSenderName();
7125
    $defaultSenderEmail = $notification->getDefaultPlatformSenderEmail();
7126
7127
    // If the parameter is set don't use the admin.
7128
    $senderName = !empty($sender['name']) ? $sender['name'] : $defaultSenderName;
7129
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $defaultSenderEmail;
7130
7131
    // Send errors to the platform admin
7132
    $email
7133
        ->getHeaders()
7134
        ->addIdHeader('Errors-To', api_get_setting('admin.administrator_email'))
7135
    ;
7136
7137
    if (!$avoidReplyToAddress && !empty($replyToAddress)) {
7138
        $email->addReplyTo(new Address($replyToAddress['mail'], $replyToAddress['name']));
7139
    }
7140
7141
    if ('true' === api_get_setting('mail.smtp_unique_sender')) {
7142
        $senderName = $defaultSenderName;
7143
        $senderEmail = $defaultSenderEmail;
7144
7145
        $email->sender(new Address($senderEmail, $senderName));
7146
    }
7147
7148
    if ($senderEmail) {
7149
        $email->from(new Address($senderEmail, $senderName));
7150
    }
7151
}
7152
7153
/**
7154
 * Sends an email
7155
 * Sender name and email can be specified, if not specified
7156
 * name and email of the platform admin are used.
7157
 *
7158
 * @param string    name of recipient
7159
 * @param string    email of recipient
7160
 * @param string    email subject
7161
 * @param string    email body
7162
 * @param string    sender name
7163
 * @param string    sender e-mail
7164
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
7165
 * @param array     data file (path and filename)
7166
 * @param bool      True for attaching a embedded file inside content html (optional)
7167
 * @param array     Additional parameters
7168
 *
7169
 * @return bool true if mail was sent
7170
 */
7171
function api_mail_html(
7172
    $recipientName,
7173
    $recipientEmail,
7174
    $subject,
7175
    $body,
7176
    $senderName = '',
7177
    $senderEmail = '',
7178
    $extra_headers = [],
7179
    $data_file = [],
7180
    $embeddedImage = false,
7181
    $additionalParameters = [],
7182
    string $sendErrorTo = null
7183
) {
7184
    $mailHelper = Container::$container->get(MailHelper::class);
7185
7186
    return $mailHelper->send(
7187
        $recipientName,
7188
        $recipientEmail,
7189
        $subject,
7190
        $body,
7191
        $senderName,
7192
        $senderEmail,
7193
        $extra_headers,
7194
        $data_file,
7195
        $embeddedImage,
7196
        $additionalParameters,
7197
        $sendErrorTo
7198
    );
7199
}
7200
7201
/**
7202
 * @param int  $tool       Possible values: GroupManager::GROUP_TOOL_*
7203
 * @param bool $showHeader
7204
 */
7205
function api_protect_course_group($tool, $showHeader = true)
7206
{
7207
    $groupId = api_get_group_id();
7208
    if (!empty($groupId)) {
7209
        if (api_is_platform_admin()) {
7210
            return true;
7211
        }
7212
7213
        if (api_is_allowed_to_edit(false, true, true)) {
7214
            return true;
7215
        }
7216
7217
        $userId = api_get_user_id();
7218
        $sessionId = api_get_session_id();
7219
        if (!empty($sessionId)) {
7220
            if (api_is_coach($sessionId, api_get_course_int_id())) {
7221
                return true;
7222
            }
7223
7224
            if (api_is_drh()) {
7225
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
7226
                    return true;
7227
                }
7228
            }
7229
        }
7230
7231
        $group = api_get_group_entity($groupId);
7232
7233
        // Group doesn't exists
7234
        if (null === $group) {
7235
            api_not_allowed($showHeader);
7236
        }
7237
7238
        // Check group access
7239
        $allow = GroupManager::userHasAccess(
7240
            $userId,
7241
            $group,
7242
            $tool
7243
        );
7244
7245
        if (!$allow) {
7246
            api_not_allowed($showHeader);
7247
        }
7248
    }
7249
7250
    return false;
7251
}
7252
7253
/**
7254
 * Check if a date is in a date range.
7255
 *
7256
 * @param datetime $startDate
7257
 * @param datetime $endDate
7258
 * @param datetime $currentDate
7259
 *
7260
 * @return bool true if date is in rage, false otherwise
7261
 */
7262
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
7263
{
7264
    $startDate = strtotime(api_get_local_time($startDate));
7265
    $endDate = strtotime(api_get_local_time($endDate));
7266
    $currentDate = strtotime(api_get_local_time($currentDate));
7267
7268
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
7269
        return true;
7270
    }
7271
7272
    return false;
7273
}
7274
7275
/**
7276
 * Eliminate the duplicates of a multidimensional array by sending the key.
7277
 *
7278
 * @param array $array multidimensional array
7279
 * @param int   $key   key to find to compare
7280
 *
7281
 * @return array
7282
 */
7283
function api_unique_multidim_array($array, $key)
7284
{
7285
    $temp_array = [];
7286
    $i = 0;
7287
    $key_array = [];
7288
7289
    foreach ($array as $val) {
7290
        if (!in_array($val[$key], $key_array)) {
7291
            $key_array[$i] = $val[$key];
7292
            $temp_array[$i] = $val;
7293
        }
7294
        $i++;
7295
    }
7296
7297
    return $temp_array;
7298
}
7299
7300
/**
7301
 * Limit the access to Session Admins when the limit_session_admin_role
7302
 * configuration variable is set to true.
7303
 */
7304
function api_protect_limit_for_session_admin()
7305
{
7306
    $limitAdmin = api_get_setting('limit_session_admin_role');
7307
    if (api_is_session_admin() && 'true' === $limitAdmin) {
7308
        api_not_allowed(true);
7309
    }
7310
}
7311
7312
/**
7313
 * Limits that a session admin has access to list users.
7314
 * When limit_session_admin_list_users configuration variable is set to true.
7315
 */
7316
function api_protect_session_admin_list_users()
7317
{
7318
    $limitAdmin = ('true' === api_get_setting('session.limit_session_admin_list_users'));
7319
7320
    if (api_is_session_admin() && true === $limitAdmin) {
7321
        api_not_allowed(true);
7322
    }
7323
}
7324
7325
/**
7326
 * @return bool
7327
 */
7328
function api_is_student_view_active(): bool
7329
{
7330
    $studentView = Session::read('studentview');
7331
7332
    return 'studentview' === $studentView;
7333
}
7334
7335
/**
7336
 * Converts string value to float value.
7337
 *
7338
 * 3.141516 => 3.141516
7339
 * 3,141516 => 3.141516
7340
 *
7341
 * @todo WIP
7342
 *
7343
 * @param string $number
7344
 *
7345
 * @return float
7346
 */
7347
function api_float_val($number)
7348
{
7349
    return (float) str_replace(',', '.', trim($number));
7350
}
7351
7352
/**
7353
 * Converts float values
7354
 * Example if $decimals = 2.
7355
 *
7356
 * 3.141516 => 3.14
7357
 * 3,141516 => 3,14
7358
 *
7359
 * @param string $number            number in iso code
7360
 * @param int    $decimals
7361
 * @param string $decimalSeparator
7362
 * @param string $thousandSeparator
7363
 *
7364
 * @return bool|string
7365
 */
7366
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
7367
{
7368
    $number = api_float_val($number);
7369
7370
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
7371
}
7372
7373
/**
7374
 * Set location url with a exit break by default.
7375
 *
7376
 * @param string $url
7377
 * @param bool   $exit
7378
 */
7379
function api_location($url, $exit = true)
7380
{
7381
    header('Location: '.$url);
7382
7383
    if ($exit) {
7384
        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...
7385
    }
7386
}
7387
7388
/**
7389
 * @param string $from
7390
 * @param string $to
7391
 *
7392
 * @return string
7393
 */
7394
function api_get_relative_path($from, $to)
7395
{
7396
    // some compatibility fixes for Windows paths
7397
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
7398
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
7399
    $from = str_replace('\\', '/', $from);
7400
    $to = str_replace('\\', '/', $to);
7401
7402
    $from = explode('/', $from);
7403
    $to = explode('/', $to);
7404
    $relPath = $to;
7405
7406
    foreach ($from as $depth => $dir) {
7407
        // find first non-matching dir
7408
        if ($dir === $to[$depth]) {
7409
            // ignore this directory
7410
            array_shift($relPath);
7411
        } else {
7412
            // get number of remaining dirs to $from
7413
            $remaining = count($from) - $depth;
7414
            if ($remaining > 1) {
7415
                // add traversals up to first matching dir
7416
                $padLength = (count($relPath) + $remaining - 1) * -1;
7417
                $relPath = array_pad($relPath, $padLength, '..');
7418
                break;
7419
            } else {
7420
                $relPath[0] = './'.$relPath[0];
7421
            }
7422
        }
7423
    }
7424
7425
    return implode('/', $relPath);
7426
}
7427
7428
/**
7429
 * @param string $template
7430
 *
7431
 * @return string
7432
 */
7433
function api_find_template($template)
7434
{
7435
    return Template::findTemplateFilePath($template);
7436
}
7437
7438
/**
7439
 * @return array
7440
 */
7441
function api_get_language_list_for_flag()
7442
{
7443
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
7444
    $sql = "SELECT english_name, isocode FROM $table
7445
            ORDER BY original_name ASC";
7446
    static $languages = [];
7447
    if (empty($languages)) {
7448
        $result = Database::query($sql);
7449
        while ($row = Database::fetch_array($result)) {
7450
            $languages[$row['english_name']] = $row['isocode'];
7451
        }
7452
        $languages['english'] = 'gb';
7453
    }
7454
7455
    return $languages;
7456
}
7457
7458
function api_create_zip(string $name): ZipStream
7459
{
7460
    $zipStreamOptions = new Archive();
7461
    $zipStreamOptions->setSendHttpHeaders(true);
7462
    $zipStreamOptions->setContentDisposition('attachment');
7463
    $zipStreamOptions->setContentType('application/x-zip');
7464
7465
    return new ZipStream($name, $zipStreamOptions);
7466
}
7467
7468
function api_get_language_translate_html(): string
7469
{
7470
    $translate = 'true' === api_get_setting('editor.translate_html');
7471
7472
    if (!$translate) {
7473
        return '';
7474
    }
7475
7476
    /*$languageList = api_get_languages();
7477
    $hideAll = '';
7478
    foreach ($languageList as $isocode => $name) {
7479
        $hideAll .= '
7480
        $(".mce-translatehtml").hide();
7481
        $("span:lang('.$isocode.')").filter(
7482
            function(e, val) {
7483
                // Only find the spans if they have set the lang
7484
                if ($(this).attr("lang") == null) {
7485
                    return false;
7486
                }
7487
                // Ignore ckeditor classes
7488
                return !this.className.match(/cke(.*)/);
7489
        }).hide();'."\n";
7490
    }*/
7491
7492
    $userInfo = api_get_user_info();
7493
    if (!empty($userInfo['language'])) {
7494
        $isoCode = $userInfo['language'];
7495
7496
        return '
7497
            $(function() {
7498
                $(".mce-translatehtml").hide();
7499
                var defaultLanguageFromUser = "'.$isoCode.'";
7500
                $("span:lang('.$isoCode.')").show();
7501
            });
7502
        ';
7503
    }
7504
7505
    return '';
7506
}
7507
7508
function api_protect_webservices()
7509
{
7510
    if (api_get_configuration_value('disable_webservices')) {
7511
        echo "Webservices are disabled. \n";
7512
        echo "To enable, add \$_configuration['disable_webservices'] = true; in configuration.php";
7513
        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...
7514
    }
7515
}
7516