Completed
Push — master ( c9546d...95f607 )
by Julito
09:41
created

public/main/inc/lib/api.lib.php (1 issue)

Code
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\Framework\Container;
13
use Chamilo\CourseBundle\Entity\CGroup;
14
use Chamilo\CourseBundle\Entity\CLp;
15
use ChamiloSession as Session;
16
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
17
use Symfony\Component\Finder\Finder;
18
use Symfony\Component\Mime\Address;
19
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
20
use Symfony\Component\Security\Core\User\UserInterface;
21
22
/**
23
 * This is a code library for Chamilo.
24
 * It is included by default in every Chamilo file (through including the global.inc.php)
25
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
26
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
27
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
28
 */
29
30
// PHP version requirement.
31
define('REQUIRED_PHP_VERSION', '7.2');
32
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
33
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
34
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
35
36
// USER STATUS CONSTANTS
37
/** global status of a user: student */
38
define('STUDENT', 5);
39
/** global status of a user: course manager */
40
define('COURSEMANAGER', 1);
41
/** global status of a user: session admin */
42
define('SESSIONADMIN', 3);
43
/** global status of a user: human ressource manager */
44
define('DRH', 4);
45
/** global status of a user: human ressource manager */
46
define('ANONYMOUS', 6);
47
/** global status of a user: low security, necessary for inserting data from
48
 * the teacher through HTMLPurifier */
49
define('COURSEMANAGERLOWSECURITY', 10);
50
// Soft user status
51
define('PLATFORM_ADMIN', 11);
52
define('SESSION_COURSE_COACH', 12);
53
define('SESSION_GENERAL_COACH', 13);
54
define('COURSE_STUDENT', 14); //student subscribed in a course
55
define('SESSION_STUDENT', 15); //student subscribed in a session course
56
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
57
define('STUDENT_BOSS', 17); // student is boss
58
define('INVITEE', 20);
59
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
60
61
// COURSE VISIBILITY CONSTANTS
62
/** only visible for course admin */
63
define('COURSE_VISIBILITY_CLOSED', 0);
64
/** only visible for users registered in the course */
65
define('COURSE_VISIBILITY_REGISTERED', 1);
66
/** Open for all registered users on the platform */
67
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
68
/** Open for the whole world */
69
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
70
/** Invisible to all except admin */
71
define('COURSE_VISIBILITY_HIDDEN', 4);
72
73
define('COURSE_REQUEST_PENDING', 0);
74
define('COURSE_REQUEST_ACCEPTED', 1);
75
define('COURSE_REQUEST_REJECTED', 2);
76
define('DELETE_ACTION_ENABLED', false);
77
78
// EMAIL SENDING RECIPIENT CONSTANTS
79
define('SEND_EMAIL_EVERYONE', 1);
80
define('SEND_EMAIL_STUDENTS', 2);
81
define('SEND_EMAIL_TEACHERS', 3);
82
83
// SESSION VISIBILITY CONSTANTS
84
define('SESSION_VISIBLE_READ_ONLY', 1);
85
define('SESSION_VISIBLE', 2);
86
define('SESSION_INVISIBLE', 3); // not available
87
define('SESSION_AVAILABLE', 4);
88
89
define('SESSION_LINK_TARGET', '_self');
90
91
define('SUBSCRIBE_ALLOWED', 1);
92
define('SUBSCRIBE_NOT_ALLOWED', 0);
93
define('UNSUBSCRIBE_ALLOWED', 1);
94
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
95
96
// SURVEY VISIBILITY CONSTANTS
97
define('SURVEY_VISIBLE_TUTOR', 0);
98
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
99
define('SURVEY_VISIBLE_PUBLIC', 2);
100
101
// CONSTANTS defining all tools, using the english version
102
/* When you add a new tool you must add it into function api_get_tools_lists() too */
103
define('TOOL_DOCUMENT', 'document');
104
define('TOOL_LP_FINAL_ITEM', 'final_item');
105
define('TOOL_READOUT_TEXT', 'readout_text');
106
define('TOOL_THUMBNAIL', 'thumbnail');
107
define('TOOL_HOTPOTATOES', 'hotpotatoes');
108
define('TOOL_CALENDAR_EVENT', 'calendar_event');
109
define('TOOL_LINK', 'link');
110
define('TOOL_LINK_CATEGORY', 'link_category');
111
define('TOOL_COURSE_DESCRIPTION', 'course_description');
112
define('TOOL_SEARCH', 'search');
113
define('TOOL_LEARNPATH', 'learnpath');
114
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
115
define('TOOL_AGENDA', 'agenda');
116
define('TOOL_ANNOUNCEMENT', 'announcement');
117
define('TOOL_FORUM', 'forum');
118
define('TOOL_FORUM_CATEGORY', 'forum_category');
119
define('TOOL_FORUM_THREAD', 'forum_thread');
120
define('TOOL_FORUM_POST', 'forum_post');
121
define('TOOL_FORUM_ATTACH', 'forum_attachment');
122
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
123
define('TOOL_THREAD', 'thread');
124
define('TOOL_POST', 'post');
125
define('TOOL_DROPBOX', 'dropbox');
126
define('TOOL_QUIZ', 'quiz');
127
define('TOOL_TEST_CATEGORY', 'test_category');
128
define('TOOL_USER', 'user');
129
define('TOOL_GROUP', 'group');
130
define('TOOL_BLOGS', 'blog_management');
131
define('TOOL_CHAT', 'chat');
132
define('TOOL_STUDENTPUBLICATION', 'student_publication');
133
define('TOOL_TRACKING', 'tracking');
134
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
135
define('TOOL_COURSE_SETTING', 'course_setting');
136
define('TOOL_BACKUP', 'backup');
137
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
138
define('TOOL_RECYCLE_COURSE', 'recycle_course');
139
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
140
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
141
define('TOOL_UPLOAD', 'file_upload');
142
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
143
define('TOOL_SURVEY', 'survey');
144
define('TOOL_WIKI', 'wiki');
145
define('TOOL_GLOSSARY', 'glossary');
146
define('TOOL_GRADEBOOK', 'gradebook');
147
define('TOOL_NOTEBOOK', 'notebook');
148
define('TOOL_ATTENDANCE', 'attendance');
149
define('TOOL_COURSE_PROGRESS', 'course_progress');
150
define('TOOL_PORTFOLIO', 'portfolio');
151
define('TOOL_PLAGIARISM', 'compilatio');
152
153
// CONSTANTS defining Chamilo interface sections
154
define('SECTION_CAMPUS', 'mycampus');
155
define('SECTION_COURSES', 'mycourses');
156
define('SECTION_CATALOG', 'catalog');
157
define('SECTION_MYPROFILE', 'myprofile');
158
define('SECTION_MYAGENDA', 'myagenda');
159
define('SECTION_COURSE_ADMIN', 'course_admin');
160
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
161
define('SECTION_MYGRADEBOOK', 'mygradebook');
162
define('SECTION_TRACKING', 'session_my_space');
163
define('SECTION_SOCIAL', 'social-network');
164
define('SECTION_DASHBOARD', 'dashboard');
165
define('SECTION_REPORTS', 'reports');
166
define('SECTION_GLOBAL', 'global');
167
define('SECTION_INCLUDE', 'include');
168
169
// CONSTANT name for local authentication source
170
define('PLATFORM_AUTH_SOURCE', 'platform');
171
define('CAS_AUTH_SOURCE', 'cas');
172
define('LDAP_AUTH_SOURCE', 'extldap');
173
174
// CONSTANT defining the default HotPotatoes files directory
175
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
176
177
// event logs types
178
define('LOG_COURSE_DELETE', 'course_deleted');
179
define('LOG_COURSE_CREATE', 'course_created');
180
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
181
182
// @todo replace 'soc_gr' with social_group
183
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
184
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
185
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
186
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
187
188
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
189
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
190
191
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
192
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
193
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
194
195
define('LOG_USER_DELETE', 'user_deleted');
196
define('LOG_USER_CREATE', 'user_created');
197
define('LOG_USER_UPDATE', 'user_updated');
198
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
199
define('LOG_USER_ENABLE', 'user_enable');
200
define('LOG_USER_DISABLE', 'user_disable');
201
define('LOG_USER_ANONYMIZE', 'user_anonymized');
202
define('LOG_USER_FIELD_CREATE', 'user_field_created');
203
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
204
define('LOG_SESSION_CREATE', 'session_created');
205
define('LOG_SESSION_DELETE', 'session_deleted');
206
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
207
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
208
define('LOG_SESSION_ADD_USER', 'session_add_user');
209
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
210
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
211
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
212
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
213
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
214
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
215
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
216
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
217
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
218
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
219
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
220
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
221
define('LOG_PROMOTION_CREATE', 'promotion_created');
222
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
223
define('LOG_CAREER_CREATE', 'career_created');
224
define('LOG_CAREER_DELETE', 'career_deleted');
225
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
226
define('LOG_WIKI_ACCESS', 'wiki_page_view');
227
// All results from an exercise
228
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
229
// Logs only the one attempt
230
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
231
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
232
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
233
234
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
235
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
236
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
237
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
238
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
239
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
240
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
241
242
// Event logs data types (max 20 chars)
243
define('LOG_COURSE_CODE', 'course_code');
244
define('LOG_COURSE_ID', 'course_id');
245
define('LOG_USER_ID', 'user_id');
246
define('LOG_USER_OBJECT', 'user_object');
247
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
248
define('LOG_SESSION_ID', 'session_id');
249
250
define('LOG_QUESTION_ID', 'question_id');
251
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
252
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
253
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
254
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
255
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
256
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
257
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
258
define('LOG_CAREER_ID', 'career_id');
259
define('LOG_PROMOTION_ID', 'promotion_id');
260
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
261
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
262
define('LOG_GRADEBOOK_ID', 'gradebook_id');
263
define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
264
define('LOG_EXERCISE_ID', 'exercise_id');
265
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
266
define('LOG_LP_ID', 'lp_id');
267
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
268
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
269
270
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
271
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
272
define('LOG_WORK_DATA', 'work_data_array');
273
274
define('LOG_MY_FOLDER_PATH', 'path');
275
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
276
277
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
278
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
279
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
280
281
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
282
283
define('LOG_QUESTION_CREATED', 'question_created');
284
define('LOG_QUESTION_UPDATED', 'question_updated');
285
define('LOG_QUESTION_DELETED', 'question_deleted');
286
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
287
288
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
289
290
//used when login_is_email setting is true
291
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
292
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
293
294
// This constant is a result of Windows OS detection, it has a boolean value:
295
// true whether the server runs on Windows OS, false otherwise.
296
define('IS_WINDOWS_OS', api_is_windows_os());
297
298
// iconv extension, for PHP5 on Windows it is installed by default.
299
define('ICONV_INSTALLED', function_exists('iconv'));
300
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
301
302
// Patterns for processing paths. Examples.
303
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
304
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
305
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
306
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
307
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
308
// basic (leaf elements)
309
define('REL_CODE_PATH', 'REL_CODE_PATH');
310
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
311
define('REL_HOME_PATH', 'REL_HOME_PATH');
312
313
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
314
define('WEB_PATH', 'WEB_PATH');
315
define('SYS_PATH', 'SYS_PATH');
316
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
317
define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
318
define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
319
320
define('REL_PATH', 'REL_PATH');
321
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
322
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
323
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
324
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
325
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
326
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
327
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
328
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
329
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
330
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
331
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
332
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
333
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
334
define('LIBRARY_PATH', 'LIBRARY_PATH');
335
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
336
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
337
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
338
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
339
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
340
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
341
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
342
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
343
344
// Relations type with Course manager
345
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
346
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
347
348
// Relations type with Human resources manager
349
define('COURSE_RELATION_TYPE_RRHH', 1);
350
define('SESSION_RELATION_TYPE_RRHH', 1);
351
352
//User image sizes
353
define('USER_IMAGE_SIZE_ORIGINAL', 1);
354
define('USER_IMAGE_SIZE_BIG', 2);
355
define('USER_IMAGE_SIZE_MEDIUM', 3);
356
define('USER_IMAGE_SIZE_SMALL', 4);
357
358
// Relation type between users
359
define('USER_UNKNOWN', 0);
360
define('USER_RELATION_TYPE_UNKNOWN', 1);
361
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
362
define('USER_RELATION_TYPE_FRIEND', 3);
363
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
364
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
365
define('USER_RELATION_TYPE_DELETED', 6);
366
define('USER_RELATION_TYPE_RRHH', 7);
367
define('USER_RELATION_TYPE_BOSS', 8);
368
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
369
370
// Gradebook link constants
371
// Please do not change existing values, they are used in the database !
372
define('GRADEBOOK_ITEM_LIMIT', 1000);
373
374
define('LINK_EXERCISE', 1);
375
define('LINK_DROPBOX', 2);
376
define('LINK_STUDENTPUBLICATION', 3);
377
define('LINK_LEARNPATH', 4);
378
define('LINK_FORUM_THREAD', 5);
379
//define('LINK_WORK',6);
380
define('LINK_ATTENDANCE', 7);
381
define('LINK_SURVEY', 8);
382
define('LINK_HOTPOTATOES', 9);
383
384
// Score display types constants
385
define('SCORE_DIV', 1); // X / Y
386
define('SCORE_PERCENT', 2); // XX %
387
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
388
define('SCORE_AVERAGE', 4); // XX %
389
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
390
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
391
define('SCORE_SIMPLE', 7); // X
392
define('SCORE_IGNORE_SPLIT', 8); //  ??
393
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
394
define('SCORE_CUSTOM', 10); // Good!
395
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
396
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
397
define('SCORE_ONLY_SCORE', 13); // X - Good!
398
define('SCORE_NUMERIC', 14);
399
400
define('SCORE_BOTH', 1);
401
define('SCORE_ONLY_DEFAULT', 2);
402
define('SCORE_ONLY_CUSTOM', 3);
403
404
// From display.lib.php
405
406
define('MAX_LENGTH_BREADCRUMB', 100);
407
define('ICON_SIZE_ATOM', 8);
408
define('ICON_SIZE_TINY', 16);
409
define('ICON_SIZE_SMALL', 22);
410
define('ICON_SIZE_MEDIUM', 32);
411
define('ICON_SIZE_LARGE', 48);
412
define('ICON_SIZE_BIG', 64);
413
define('ICON_SIZE_HUGE', 128);
414
define('SHOW_TEXT_NEAR_ICONS', false);
415
416
// Session catalog
417
define('CATALOG_COURSES', 0);
418
define('CATALOG_SESSIONS', 1);
419
define('CATALOG_COURSES_SESSIONS', 2);
420
421
// Hook type events, pre-process and post-process.
422
// All means to be executed for both hook event types
423
define('HOOK_EVENT_TYPE_PRE', 0);
424
define('HOOK_EVENT_TYPE_POST', 1);
425
define('HOOK_EVENT_TYPE_ALL', 10);
426
427
define('CAREER_STATUS_ACTIVE', 1);
428
define('CAREER_STATUS_INACTIVE', 0);
429
430
define('PROMOTION_STATUS_ACTIVE', 1);
431
define('PROMOTION_STATUS_INACTIVE', 0);
432
433
// Group permissions
434
define('GROUP_PERMISSION_OPEN', '1');
435
define('GROUP_PERMISSION_CLOSED', '2');
436
437
// Group user permissions
438
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
439
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
440
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
441
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
442
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
443
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
444
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
445
446
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
447
define('GROUP_IMAGE_SIZE_BIG', 2);
448
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
449
define('GROUP_IMAGE_SIZE_SMALL', 4);
450
define('GROUP_TITLE_LENGTH', 50);
451
452
// Exercise
453
// @todo move into a class
454
define('ALL_ON_ONE_PAGE', 1);
455
define('ONE_PER_PAGE', 2);
456
457
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
458
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
459
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
460
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
461
462
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
463
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
464
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
465
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
466
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
467
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
468
define('RESULT_DISABLE_RANKING', 6);
469
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
470
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
471
472
define('EXERCISE_MAX_NAME_SIZE', 80);
473
474
// Question types (edit next array as well when adding values)
475
// @todo move into a class
476
define('UNIQUE_ANSWER', 1);
477
define('MULTIPLE_ANSWER', 2);
478
define('FILL_IN_BLANKS', 3);
479
define('MATCHING', 4);
480
define('FREE_ANSWER', 5);
481
define('HOT_SPOT', 6);
482
define('HOT_SPOT_ORDER', 7);
483
define('HOT_SPOT_DELINEATION', 8);
484
define('MULTIPLE_ANSWER_COMBINATION', 9);
485
define('UNIQUE_ANSWER_NO_OPTION', 10);
486
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
487
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
488
define('ORAL_EXPRESSION', 13);
489
define('GLOBAL_MULTIPLE_ANSWER', 14);
490
define('MEDIA_QUESTION', 15);
491
define('CALCULATED_ANSWER', 16);
492
define('UNIQUE_ANSWER_IMAGE', 17);
493
define('DRAGGABLE', 18);
494
define('MATCHING_DRAGGABLE', 19);
495
define('ANNOTATION', 20);
496
define('READING_COMPREHENSION', 21);
497
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
498
499
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
500
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
501
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
502
503
// Question selection type
504
define('EX_Q_SELECTION_ORDERED', 1);
505
define('EX_Q_SELECTION_RANDOM', 2);
506
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
507
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
508
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
509
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
510
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
511
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
512
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
513
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
514
515
// Used to save the skill_rel_item table
516
define('ITEM_TYPE_EXERCISE', 1);
517
define('ITEM_TYPE_HOTPOTATOES', 2);
518
define('ITEM_TYPE_LINK', 3);
519
define('ITEM_TYPE_LEARNPATH', 4);
520
define('ITEM_TYPE_GRADEBOOK', 5);
521
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
522
//define('ITEM_TYPE_FORUM', 7);
523
define('ITEM_TYPE_ATTENDANCE', 8);
524
define('ITEM_TYPE_SURVEY', 9);
525
define('ITEM_TYPE_FORUM_THREAD', 10);
526
527
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
528
define(
529
    'QUESTION_TYPES',
530
    UNIQUE_ANSWER.':'.
531
    MULTIPLE_ANSWER.':'.
532
    FILL_IN_BLANKS.':'.
533
    MATCHING.':'.
534
    FREE_ANSWER.':'.
535
    HOT_SPOT.':'.
536
    HOT_SPOT_ORDER.':'.
537
    HOT_SPOT_DELINEATION.':'.
538
    MULTIPLE_ANSWER_COMBINATION.':'.
539
    UNIQUE_ANSWER_NO_OPTION.':'.
540
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
541
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
542
    ORAL_EXPRESSION.':'.
543
    GLOBAL_MULTIPLE_ANSWER.':'.
544
    MEDIA_QUESTION.':'.
545
    CALCULATED_ANSWER.':'.
546
    UNIQUE_ANSWER_IMAGE.':'.
547
    DRAGGABLE.':'.
548
    MATCHING_DRAGGABLE.':'.
549
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
550
    ANNOTATION
551
);
552
553
//Some alias used in the QTI exports
554
define('MCUA', 1);
555
define('TF', 1);
556
define('MCMA', 2);
557
define('FIB', 3);
558
559
// Skills
560
define('SKILL_TYPE_REQUIREMENT', 'required');
561
define('SKILL_TYPE_ACQUIRED', 'acquired');
562
define('SKILL_TYPE_BOTH', 'both');
563
564
// Message
565
define('MESSAGE_STATUS_NEW', '0');
566
define('MESSAGE_STATUS_UNREAD', '1');
567
//2 ??
568
define('MESSAGE_STATUS_DELETED', '3');
569
define('MESSAGE_STATUS_OUTBOX', '4');
570
define('MESSAGE_STATUS_INVITATION_PENDING', '5');
571
define('MESSAGE_STATUS_INVITATION_ACCEPTED', '6');
572
define('MESSAGE_STATUS_INVITATION_DENIED', '7');
573
define('MESSAGE_STATUS_WALL', '8');
574
define('MESSAGE_STATUS_WALL_DELETE', '9');
575
define('MESSAGE_STATUS_WALL_POST', '10');
576
define('MESSAGE_STATUS_CONVERSATION', '11');
577
define('MESSAGE_STATUS_FORUM', '12');
578
define('MESSAGE_STATUS_PROMOTED', '13');
579
580
// Images
581
define('IMAGE_WALL_SMALL_SIZE', 200);
582
define('IMAGE_WALL_MEDIUM_SIZE', 500);
583
define('IMAGE_WALL_BIG_SIZE', 2000);
584
define('IMAGE_WALL_SMALL', 'small');
585
define('IMAGE_WALL_MEDIUM', 'medium');
586
define('IMAGE_WALL_BIG', 'big');
587
588
// Social PLUGIN PLACES
589
define('SOCIAL_LEFT_PLUGIN', 1);
590
define('SOCIAL_CENTER_PLUGIN', 2);
591
define('SOCIAL_RIGHT_PLUGIN', 3);
592
define('CUT_GROUP_NAME', 50);
593
594
/**
595
 * FormValidator Filter.
596
 */
597
define('NO_HTML', 1);
598
define('STUDENT_HTML', 2);
599
define('TEACHER_HTML', 3);
600
define('STUDENT_HTML_FULLPAGE', 4);
601
define('TEACHER_HTML_FULLPAGE', 5);
602
603
// Timeline
604
define('TIMELINE_STATUS_ACTIVE', '1');
605
define('TIMELINE_STATUS_INACTIVE', '2');
606
607
// Event email template class
608
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
609
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
610
611
// Course home
612
define('SHORTCUTS_HORIZONTAL', 0);
613
define('SHORTCUTS_VERTICAL', 1);
614
615
// Image class
616
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
617
618
// Course copy
619
define('FILE_SKIP', 1);
620
define('FILE_RENAME', 2);
621
define('FILE_OVERWRITE', 3);
622
define('UTF8_CONVERT', false); //false by default
623
624
define('DOCUMENT', 'file');
625
define('FOLDER', 'folder');
626
627
define('RESOURCE_ASSET', 'asset');
628
define('RESOURCE_DOCUMENT', 'document');
629
define('RESOURCE_GLOSSARY', 'glossary');
630
define('RESOURCE_EVENT', 'calendar_event');
631
define('RESOURCE_LINK', 'link');
632
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
633
define('RESOURCE_LEARNPATH', 'learnpath');
634
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
635
define('RESOURCE_ANNOUNCEMENT', 'announcement');
636
define('RESOURCE_FORUM', 'forum');
637
define('RESOURCE_FORUMTOPIC', 'thread');
638
define('RESOURCE_FORUMPOST', 'post');
639
define('RESOURCE_QUIZ', 'quiz');
640
define('RESOURCE_TEST_CATEGORY', 'test_category');
641
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
642
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
643
define('RESOURCE_LINKCATEGORY', 'Link_Category');
644
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
645
define('RESOURCE_SCORM', 'Scorm');
646
define('RESOURCE_SURVEY', 'survey');
647
define('RESOURCE_SURVEYQUESTION', 'survey_question');
648
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
649
define('RESOURCE_WIKI', 'wiki');
650
define('RESOURCE_THEMATIC', 'thematic');
651
define('RESOURCE_ATTENDANCE', 'attendance');
652
define('RESOURCE_WORK', 'work');
653
define('RESOURCE_SESSION_COURSE', 'session_course');
654
define('RESOURCE_GRADEBOOK', 'gradebook');
655
define('ADD_THEMATIC_PLAN', 6);
656
657
// Max online users to show per page (whoisonline)
658
define('MAX_ONLINE_USERS', 12);
659
660
// Number of characters maximum to show in preview of course blog posts
661
define('BLOG_MAX_PREVIEW_CHARS', 800);
662
// HTML string to replace with a 'Read more...' link
663
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
664
665
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
666
// To remove CKeditor libs from HTML, set this constant to true before loading
667
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
668
    define('CHAMILO_LOAD_WYSIWYG', true);
669
}
670
671
/* Constants for course home */
672
define('TOOL_PUBLIC', 'Public');
673
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
674
define('TOOL_COURSE_ADMIN', 'courseAdmin');
675
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
676
define('TOOL_AUTHORING', 'toolauthoring');
677
define('TOOL_INTERACTION', 'toolinteraction');
678
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
679
define('TOOL_ADMIN', 'tooladmin');
680
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
681
define('TOOL_DRH', 'tool_drh');
682
define('TOOL_STUDENT_VIEW', 'toolstudentview');
683
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
684
685
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
686
// some constants to avoid serialize string keys on serialized data array
687
define('SE_COURSE_ID', 0);
688
define('SE_TOOL_ID', 1);
689
define('SE_DATA', 2);
690
define('SE_USER', 3);
691
692
// in some cases we need top differenciate xapian documents of the same tool
693
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
694
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
695
696
// xapian prefixes
697
define('XAPIAN_PREFIX_COURSEID', 'C');
698
define('XAPIAN_PREFIX_TOOLID', 'O');
699
700
/**
701
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
702
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
703
 *
704
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
705
706
 *
707
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
708
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
709
 *
710
 * @return string the requested path or the converted path
711
 *
712
 * Notes about the current behaviour model:
713
 * 1. Windows back-slashes are converted to slashes in the result.
714
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
715
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
716
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
717
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
718
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
719
 * It has not been identified as needed yet.
720
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
721
 *
722
 * For examples go to: *
723
 * See main/admin/system_status.php?section=paths
724
 *
725
 * Vchamilo changes : allow using an alternate configuration
726
 * to get vchamilo  instance paths
727
 */
728
function api_get_path($path = '', $configuration = [])
729
{
730
    global $paths;
731
732
    // get proper configuration data if exists
733
    global $_configuration;
734
735
    $emptyConfigurationParam = false;
736
    if (empty($configuration)) {
737
        $configuration = (array) $_configuration;
738
        $emptyConfigurationParam = true;
739
    }
740
741
    $root_sys = Container::getProjectDir();
742
743
    $root_web = '';
744
    // If no $root_web has been set so far *and* no custom config has been passed to the function
745
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
746
    /*
747
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
748
        // Resolve master hostname.
749
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
750
            $root_web = $configuration['root_web'];
751
        } else {
752
            $root_web = '';
753
            // Try guess it from server.
754
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
755
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
756
                    $root_rel = substr($requested_page_rel, 0, $pos);
757
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
758
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
759
                    $server_name =
760
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
761
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
762
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
763
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
764
                                    : 'localhost')));
765
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
766
                        && (($server_protocol == 'http'
767
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
768
                    ) {
769
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
770
                    }
771
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
772
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
773
                }
774
                // Here we give up, so we don't touch anything.
775
            }
776
        }
777
    }*/
778
    if (isset(Container::$container)) {
779
        $root_web = Container::$container->get('router')->generate(
780
            'home',
781
            [],
782
            UrlGeneratorInterface::ABSOLUTE_URL
783
        );
784
    }
785
786
    if (isset($configuration['multiple_access_urls']) &&
787
        $configuration['multiple_access_urls']
788
    ) {
789
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
790
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
791
            // We look into the DB the function api_get_access_url
792
            $urlInfo = api_get_access_url($configuration['access_url']);
793
            // Avoid default value
794
            $defaultValues = ['http://localhost/', 'https://localhost/'];
795
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
796
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
797
            }
798
        }
799
    }
800
801
    $paths = [
802
        WEB_PATH => $root_web,
803
        SYMFONY_SYS_PATH => $root_sys,
804
        SYS_PATH => $root_sys.'public/',
805
        REL_PATH => '',
806
        CONFIGURATION_PATH => 'app/config/',
807
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
808
809
        REL_COURSE_PATH => '',
810
        REL_CODE_PATH => '/main/',
811
812
        SYS_CODE_PATH => $root_sys.'public/main/',
813
        SYS_CSS_PATH => $root_sys.'public/build/css/',
814
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
815
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
816
       // SYS_UPLOAD_PATH => 'var/upload/',
817
        SYS_TEST_PATH => $root_sys.'tests/',
818
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
819
        SYS_PUBLIC_PATH => $root_sys.'public/',
820
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
821
822
        WEB_CODE_PATH => $root_web.'main/',
823
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
824
        WEB_COURSE_PATH => $root_web.'course/',
825
        WEB_IMG_PATH => $root_web.'img/',
826
        WEB_CSS_PATH => $root_web.'build/css/',
827
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
828
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
829
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
830
        WEB_PLUGIN_PATH => $root_web.'plugin/',
831
       // WEB_ARCHIVE_PATH => 'var/cache/',
832
        //WEB_UPLOAD_PATH => 'var/upload/',
833
        WEB_PUBLIC_PATH => $root_web,
834
    ];
835
836
    $root_rel = '';
837
838
    // Dealing with trailing slashes.
839
    $rootWebWithSlash = api_add_trailing_slash($root_web);
840
    $root_sys = api_add_trailing_slash($root_sys);
841
    $root_rel = api_add_trailing_slash($root_rel);
842
843
    // Initialization of a table that contains common-purpose paths.
844
    /*$paths[$root_web][REL_PATH] = $root_rel;
845
    $paths[$root_web][REL_CODE_PATH] = $root_rel.$code_folder;
846
    $paths[$root_web][WEB_PATH] = $rootWebWithSlash;
847
    $paths[$root_web][WEB_CODE_PATH] = $rootWebWithSlash.'main/';
848
    $paths[$root_web][WEB_COURSE_PATH] = $rootWebWithSlash.$course_folder;
849
    $paths[$root_web][WEB_PLUGIN_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_PATH];
850
    $paths[$root_web][WEB_PLUGIN_ASSET_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_ASSET_PATH];
851
    $paths[$root_web][WEB_ARCHIVE_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_ARCHIVE_PATH];
852
    $paths[$root_web][WEB_CSS_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_CSS_PATH];
853
    //$paths[$root_web][WEB_UPLOAD_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_UPLOAD_PATH];
854
    $paths[$root_web][WEB_PUBLIC_PATH] = $rootWebWithSlash;
855
856
    $paths[$root_web][WEB_IMG_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_IMG_PATH];
857
    $paths[$root_web][WEB_LIBRARY_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_PATH];
858
    $paths[$root_web][WEB_LIBRARY_JS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_JS_PATH];
859
    $paths[$root_web][WEB_AJAX_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_AJAX_PATH];
860
861
    $paths[$root_web][SYS_PATH] = $root_sys;
862
    $paths[$root_web][SYS_CODE_PATH] = $root_sys.$code_folder;
863
    $paths[$root_web][SYS_TEST_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_TEST_PATH];
864
    $paths[$root_web][SYS_TEMPLATE_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_TEMPLATE_PATH];
865
    $paths[$root_web][SYS_PUBLIC_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PUBLIC_PATH];
866
    $paths[$root_web][SYS_CSS_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_CSS_PATH];
867
    $paths[$root_web][SYS_FONTS_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_FONTS_PATH];
868
    $paths[$root_web][SYS_ARCHIVE_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_ARCHIVE_PATH];
869
    $paths[$root_web][SYS_APP_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_APP_PATH];
870
    $paths[$root_web][SYS_UPLOAD_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_UPLOAD_PATH];
871
    $paths[$root_web][SYS_PLUGIN_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PLUGIN_PATH];
872
    $paths[$root_web][LIBRARY_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][LIBRARY_PATH];
873
    $paths[$root_web][CONFIGURATION_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][CONFIGURATION_PATH];*/
874
875
    global $virtualChamilo;
876
    if (!empty($virtualChamilo)) {
877
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
878
        $paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
879
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
880
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
881
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
882
883
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
884
885
        // RewriteEngine On
886
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
887
888
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
889
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
890
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
891
    }
892
893
    $path = trim($path);
894
895
    // Retrieving a common-purpose path.
896
    if (isset($paths[$path])) {
897
        return $paths[$path];
898
    }
899
900
    return false;
901
}
902
903
/**
904
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
905
 *
906
 * @param string $path the input path
907
 *
908
 * @return string returns the modified path
909
 */
910
function api_add_trailing_slash($path)
911
{
912
    return '/' == substr($path, -1) ? $path : $path.'/';
913
}
914
915
/**
916
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
917
 *
918
 * @param string $path the input path
919
 *
920
 * @return string returns the modified path
921
 */
922
function api_remove_trailing_slash($path)
923
{
924
    return '/' == substr($path, -1) ? substr($path, 0, -1) : $path;
925
}
926
927
/**
928
 * Checks the RFC 3986 syntax of a given URL.
929
 *
930
 * @param string $url      the URL to be checked
931
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
932
 *
933
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
934
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
935
 *
936
 * @see http://drupal.org
937
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
938
 * @see http://bugs.php.net/51192
939
 */
940
function api_valid_url($url, $absolute = false)
941
{
942
    if ($absolute) {
943
        if (preg_match("
944
            /^                                                      # Start at the beginning of the text
945
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
946
            (?:                                                     # Userinfo (optional) which is typically
947
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
948
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
949
            )?
950
            (?:
951
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
952
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
953
            )
954
            (?::[0-9]+)?                                            # Server port number (optional)
955
            (?:[\/|\?]
956
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
957
            *)?
958
            $/xi", $url)) {
959
            return $url;
960
        }
961
962
        return false;
963
    } else {
964
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
965
    }
966
}
967
968
/**
969
 * Checks whether a given string looks roughly like an email address.
970
 *
971
 * @param string $address the e-mail address to be checked
972
 *
973
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
974
 */
975
function api_valid_email($address)
976
{
977
    return filter_var($address, FILTER_VALIDATE_EMAIL);
978
}
979
980
/* PROTECTION FUNCTIONS
981
   Use these functions to protect your scripts. */
982
983
/**
984
 * Function used to protect a course script.
985
 * The function blocks access when
986
 * - there is no $_SESSION["_course"] defined; or
987
 * - $is_allowed_in_course is set to false (this depends on the course
988
 * visibility and user status).
989
 *
990
 * This is only the first proposal, test and improve!
991
 *
992
 * @param bool Option to print headers when displaying error message. Default: false
993
 * @param bool whether session admins should be allowed or not
994
 * @param string $checkTool check if tool is available for users (user, group)
995
 *
996
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
997
 *
998
 * @todo replace global variable
999
 *
1000
 * @author Roan Embrechts
1001
 */
1002
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
1003
{
1004
    $course_info = api_get_course_info();
1005
    if (empty($course_info)) {
1006
        api_not_allowed($print_headers);
1007
1008
        return false;
1009
    }
1010
1011
    if (api_is_drh()) {
1012
        return true;
1013
    }
1014
1015
    // Session admin has access to course
1016
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1017
    if ($sessionAccess) {
1018
        $allow_session_admins = true;
1019
    }
1020
1021
    if (api_is_platform_admin($allow_session_admins)) {
1022
        return true;
1023
    }
1024
1025
    $isAllowedInCourse = api_is_allowed_in_course();
1026
    $is_visible = false;
1027
    if (isset($course_info) && isset($course_info['visibility'])) {
1028
        switch ($course_info['visibility']) {
1029
            default:
1030
            case COURSE_VISIBILITY_CLOSED:
1031
                // Completely closed: the course is only accessible to the teachers. - 0
1032
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1033
                    $is_visible = true;
1034
                }
1035
                break;
1036
            case COURSE_VISIBILITY_REGISTERED:
1037
                // Private - access authorized to course members only - 1
1038
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1039
                    $is_visible = true;
1040
                }
1041
                break;
1042
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1043
                // Open - access allowed for users registered on the platform - 2
1044
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1045
                    $is_visible = true;
1046
                }
1047
                break;
1048
            case COURSE_VISIBILITY_OPEN_WORLD:
1049
                //Open - access allowed for the whole world - 3
1050
                $is_visible = true;
1051
                break;
1052
            case COURSE_VISIBILITY_HIDDEN:
1053
                //Completely closed: the course is only accessible to the teachers. - 0
1054
                if (api_is_platform_admin()) {
1055
                    $is_visible = true;
1056
                }
1057
                break;
1058
        }
1059
1060
        //If password is set and user is not registered to the course then the course is not visible
1061
        if (false == $isAllowedInCourse &&
1062
            isset($course_info['registration_code']) &&
1063
            !empty($course_info['registration_code'])
1064
        ) {
1065
            $is_visible = false;
1066
        }
1067
    }
1068
1069
    if (!empty($checkTool)) {
1070
        if (!api_is_allowed_to_edit(true, true, true)) {
1071
            $toolInfo = api_get_tool_information_by_name($checkTool);
1072
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1073
                api_not_allowed(true);
1074
1075
                return false;
1076
            }
1077
        }
1078
    }
1079
1080
    // Check session visibility
1081
    $session_id = api_get_session_id();
1082
1083
    if (!empty($session_id)) {
1084
        // $isAllowedInCourse was set in local.inc.php
1085
        if (!$isAllowedInCourse) {
1086
            $is_visible = false;
1087
        }
1088
    }
1089
1090
    if (!$is_visible) {
1091
        api_not_allowed($print_headers);
1092
1093
        return false;
1094
    }
1095
1096
    return true;
1097
}
1098
1099
/**
1100
 * Function used to protect an admin script.
1101
 *
1102
 * The function blocks access when the user has no platform admin rights
1103
 * with an error message printed on default output
1104
 *
1105
 * @param bool Whether to allow session admins as well
1106
 * @param bool Whether to allow HR directors as well
1107
 * @param string An optional message (already passed through get_lang)
1108
 *
1109
 * @return bool True if user is allowed, false otherwise.
1110
 *              The function also outputs an error message in case not allowed
1111
 *
1112
 * @author Roan Embrechts (original author)
1113
 */
1114
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1115
{
1116
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1117
        api_not_allowed(true, $message);
1118
1119
        return false;
1120
    }
1121
1122
    return true;
1123
}
1124
1125
/**
1126
 * Function used to protect a teacher script.
1127
 * The function blocks access when the user has no teacher rights.
1128
 *
1129
 * @return bool True if the current user can access the script, false otherwise
1130
 *
1131
 * @author Yoselyn Castillo
1132
 */
1133
function api_protect_teacher_script()
1134
{
1135
    if (!api_is_allowed_to_edit()) {
1136
        api_not_allowed(true);
1137
1138
        return false;
1139
    }
1140
1141
    return true;
1142
}
1143
1144
/**
1145
 * Function used to prevent anonymous users from accessing a script.
1146
 *
1147
 * @param bool|true $printHeaders
1148
 *
1149
 * @author Roan Embrechts
1150
 *
1151
 * @return bool
1152
 */
1153
function api_block_anonymous_users($printHeaders = true)
1154
{
1155
    $user = api_get_user_info();
1156
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1157
        api_not_allowed($printHeaders);
1158
1159
        return false;
1160
    }
1161
1162
    return true;
1163
}
1164
1165
/**
1166
 * Returns a rough evaluation of the browser's name and version based on very
1167
 * simple regexp.
1168
 *
1169
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1170
 */
1171
function api_get_navigator()
1172
{
1173
    $navigator = 'Unknown';
1174
    $version = 0;
1175
1176
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1177
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1178
    }
1179
1180
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1181
        $navigator = 'Opera';
1182
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1183
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1184
        $navigator = 'Edge';
1185
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1186
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1187
        $navigator = 'Internet Explorer';
1188
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1189
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1190
        $navigator = 'Chrome';
1191
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1192
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1193
        $navigator = 'Safari';
1194
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1195
            // If this Safari does have the "Version/" string in its user agent
1196
            // then use that as a version indicator rather than what's after
1197
            // "Safari/" which is rather a "build number" or something
1198
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1199
        } else {
1200
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1201
        }
1202
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1203
        $navigator = 'Firefox';
1204
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1205
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1206
        $navigator = 'Netscape';
1207
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1208
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1209
        } else {
1210
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1211
        }
1212
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1213
        $navigator = 'Konqueror';
1214
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1215
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1216
        $navigator = 'AppleWebKit';
1217
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1218
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1219
        $navigator = 'Mozilla';
1220
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1221
    }
1222
1223
    // Now cut extra stuff around (mostly *after*) the version number
1224
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1225
1226
    if (false === strpos($version, '.')) {
1227
        $version = number_format(doubleval($version), 1);
1228
    }
1229
1230
    return ['name' => $navigator, 'version' => $version];
1231
}
1232
1233
/**
1234
 * @return true if user self registration is allowed, false otherwise
1235
 */
1236
function api_is_self_registration_allowed()
1237
{
1238
    return isset($GLOBALS['allowSelfReg']) ? $GLOBALS['allowSelfReg'] : false;
1239
}
1240
1241
/**
1242
 * This function returns the id of the user which is stored in the $_user array.
1243
 *
1244
 * example: The function can be used to check if a user is logged in
1245
 *          if (api_get_user_id())
1246
 *
1247
 * @return int the id of the current user, 0 if is empty
1248
 */
1249
function api_get_user_id()
1250
{
1251
    $userInfo = Session::read('_user');
1252
    if ($userInfo && isset($userInfo['user_id'])) {
1253
        return (int) $userInfo['user_id'];
1254
    }
1255
1256
    return 0;
1257
}
1258
1259
/**
1260
 * Gets the list of courses a specific user is subscribed to.
1261
 *
1262
 * @param int       User ID
1263
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1264
 *
1265
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1266
 *
1267
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1268
 */
1269
function api_get_user_courses($userId, $fetch_session = true)
1270
{
1271
    // Get out if not integer
1272
    if ($userId != strval(intval($userId))) {
1273
        return [];
1274
    }
1275
1276
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1277
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1278
1279
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1280
            FROM $t_course cc, $t_course_user cu
1281
            WHERE
1282
                cc.id = cu.c_id AND
1283
                cu.user_id = $userId AND
1284
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1285
    $result = Database::query($sql);
1286
    if (false === $result) {
1287
        return [];
1288
    }
1289
1290
    $courses = [];
1291
    while ($row = Database::fetch_array($result)) {
1292
        // we only need the database name of the course
1293
        $courses[] = $row;
1294
    }
1295
1296
    return $courses;
1297
}
1298
1299
/**
1300
 * Formats user information into a standard array
1301
 * This function should be only used inside api_get_user_info().
1302
 *
1303
 * @param array Non-standard user array
1304
 * @param bool $add_password
1305
 * @param bool $loadAvatars  turn off to improve performance
1306
 *
1307
 * @return array Standard user array
1308
 */
1309
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1310
{
1311
    $result = [];
1312
1313
    if (!isset($user['id'])) {
1314
        return [];
1315
    }
1316
1317
    $result['firstname'] = null;
1318
    $result['lastname'] = null;
1319
1320
    if (isset($user['firstname']) && isset($user['lastname'])) {
1321
        // with only lowercase
1322
        $result['firstname'] = $user['firstname'];
1323
        $result['lastname'] = $user['lastname'];
1324
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1325
        // with uppercase letters
1326
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1327
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1328
    }
1329
1330
    if (isset($user['email'])) {
1331
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1332
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1333
    } else {
1334
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1335
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1336
    }
1337
1338
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1339
    $result['complete_name_with_username'] = $result['complete_name'];
1340
1341
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1342
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1343
    }
1344
1345
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1346
    if (!empty($user['email'])) {
1347
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1348
        if ($showEmail) {
1349
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1350
        }
1351
    } else {
1352
        $result['complete_name_with_email'] = $result['complete_name'];
1353
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1354
    }
1355
1356
    // Kept for historical reasons
1357
    $result['firstName'] = $result['firstname'];
1358
    $result['lastName'] = $result['lastname'];
1359
1360
    $attributes = [
1361
        'phone',
1362
        'address',
1363
        'picture_uri',
1364
        'official_code',
1365
        'status',
1366
        'active',
1367
        'auth_source',
1368
        'username',
1369
        'theme',
1370
        'language',
1371
        'creator_id',
1372
        'registration_date',
1373
        'hr_dept_id',
1374
        'expiration_date',
1375
        'last_login',
1376
        'user_is_online',
1377
    ];
1378
1379
    if ('true' === api_get_setting('extended_profile')) {
1380
        $attributes[] = 'competences';
1381
        $attributes[] = 'diplomas';
1382
        $attributes[] = 'teach';
1383
        $attributes[] = 'openarea';
1384
    }
1385
1386
    foreach ($attributes as $attribute) {
1387
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1388
    }
1389
1390
    $user_id = (int) $user['id'];
1391
    // Maintain the user_id index for backwards compatibility
1392
    $result['user_id'] = $result['id'] = $user_id;
1393
1394
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1395
    $result['has_certificates'] = 0;
1396
    if (!empty($hasCertificates)) {
1397
        $result['has_certificates'] = 1;
1398
    }
1399
1400
    $result['icon_status'] = '';
1401
    $result['icon_status_medium'] = '';
1402
    $result['is_admin'] = UserManager::is_admin($user_id);
1403
1404
    // Getting user avatar.
1405
    if ($loadAvatars) {
1406
        $result['avatar'] = '';
1407
        $result['avatar_no_query'] = '';
1408
        $result['avatar_small'] = '';
1409
        $result['avatar_medium'] = '';
1410
1411
        /*if (!isset($user['avatar'])) {
1412
            $originalFile = UserManager::getUserPicture(
1413
                $user_id,
1414
                USER_IMAGE_SIZE_ORIGINAL,
1415
                null,
1416
                $result
1417
            );
1418
            $result['avatar'] = $originalFile;
1419
            $avatarString = explode('?', $result['avatar']);
1420
            $result['avatar_no_query'] = reset($avatarString);
1421
        } else {
1422
            $result['avatar'] = $user['avatar'];
1423
            $avatarString = explode('?', $user['avatar']);
1424
            $result['avatar_no_query'] = reset($avatarString);
1425
        }
1426
1427
        if (!isset($user['avatar_small'])) {
1428
            $smallFile = UserManager::getUserPicture(
1429
                $user_id,
1430
                USER_IMAGE_SIZE_SMALL,
1431
                null,
1432
                $result
1433
            );
1434
            $result['avatar_small'] = $smallFile;
1435
        } else {
1436
            $result['avatar_small'] = $user['avatar_small'];
1437
        }
1438
1439
        if (!isset($user['avatar_medium'])) {
1440
            $mediumFile = UserManager::getUserPicture(
1441
                $user_id,
1442
                USER_IMAGE_SIZE_MEDIUM,
1443
                null,
1444
                $result
1445
            );
1446
            $result['avatar_medium'] = $mediumFile;
1447
        } else {
1448
            $result['avatar_medium'] = $user['avatar_medium'];
1449
        }*/
1450
1451
        $urlImg = api_get_path(WEB_IMG_PATH);
1452
        $iconStatus = '';
1453
        $iconStatusMedium = '';
1454
        $label = '';
1455
        switch ($result['status']) {
1456
            case STUDENT:
1457
                if ($result['has_certificates']) {
1458
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1459
                    $label = get_lang('Graduated');
1460
                } else {
1461
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1462
                    $label = get_lang('Student');
1463
                }
1464
                break;
1465
            case COURSEMANAGER:
1466
                if ($result['is_admin']) {
1467
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1468
                    $label = get_lang('Admin');
1469
                } else {
1470
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1471
                    $label = get_lang('Teacher');
1472
                }
1473
                break;
1474
            case STUDENT_BOSS:
1475
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1476
                $label = get_lang('StudentBoss');
1477
                break;
1478
        }
1479
1480
        if (!empty($iconStatus)) {
1481
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1482
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1483
        }
1484
1485
        $result['icon_status'] = $iconStatus;
1486
        $result['icon_status_label'] = $label;
1487
        $result['icon_status_medium'] = $iconStatusMedium;
1488
    }
1489
1490
    if (isset($user['user_is_online'])) {
1491
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1492
    }
1493
    if (isset($user['user_is_online_in_chat'])) {
1494
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1495
    }
1496
1497
    if ($add_password) {
1498
        $result['password'] = $user['password'];
1499
    }
1500
1501
    if (isset($result['profile_completed'])) {
1502
        $result['profile_completed'] = $user['profile_completed'];
1503
    }
1504
1505
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1506
1507
    // Send message link
1508
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1509
    $result['complete_name_with_message_link'] = Display::url(
1510
        $result['complete_name_with_username'],
1511
        $sendMessage,
1512
        ['class' => 'ajax']
1513
    );
1514
1515
    if (isset($user['extra'])) {
1516
        $result['extra'] = $user['extra'];
1517
    }
1518
1519
    return $result;
1520
}
1521
1522
/**
1523
 * Finds all the information about a user.
1524
 * If no parameter is passed you find all the information about the current user.
1525
 *
1526
 * @param int  $user_id
1527
 * @param bool $checkIfUserOnline
1528
 * @param bool $showPassword
1529
 * @param bool $loadExtraData
1530
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1531
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1532
 * @param bool $updateCache              update apc cache if exists
1533
 *
1534
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1535
 *
1536
 * @author Patrick Cool <[email protected]>
1537
 * @author Julio Montoya
1538
 *
1539
 * @version 21 September 2004
1540
 */
1541
function api_get_user_info(
1542
    $user_id = 0,
1543
    $checkIfUserOnline = false,
1544
    $showPassword = false,
1545
    $loadExtraData = false,
1546
    $loadOnlyVisibleExtraData = false,
1547
    $loadAvatars = true,
1548
    $updateCache = false
1549
) {
1550
    // Make sure user_id is safe
1551
    $user_id = (int) $user_id;
1552
    $user = false;
1553
    if (empty($user_id)) {
1554
        $userFromSession = Session::read('_user');
1555
        if (isset($userFromSession) && !empty($userFromSession)) {
1556
            return $userFromSession;
1557
            /*
1558
            return _api_format_user(
1559
                $userFromSession,
1560
                $showPassword,
1561
                $loadAvatars
1562
            );*/
1563
        }
1564
1565
        return false;
1566
    }
1567
1568
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1569
            WHERE id = $user_id";
1570
    $result = Database::query($sql);
1571
    if (Database::num_rows($result) > 0) {
1572
        $result_array = Database::fetch_array($result);
1573
        $result_array['user_is_online_in_chat'] = 0;
1574
        if ($checkIfUserOnline) {
1575
            $use_status_in_platform = user_is_online($user_id);
1576
            $result_array['user_is_online'] = $use_status_in_platform;
1577
            $user_online_in_chat = 0;
1578
            if ($use_status_in_platform) {
1579
                $user_status = UserManager::get_extra_user_data_by_field(
1580
                    $user_id,
1581
                    'user_chat_status',
1582
                    false,
1583
                    true
1584
                );
1585
                if (1 == (int) $user_status['user_chat_status']) {
1586
                    $user_online_in_chat = 1;
1587
                }
1588
            }
1589
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1590
        }
1591
1592
        if ($loadExtraData) {
1593
            $fieldValue = new ExtraFieldValue('user');
1594
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1595
                $user_id,
1596
                $loadOnlyVisibleExtraData
1597
            );
1598
        }
1599
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1600
    }
1601
1602
    return $user;
1603
}
1604
1605
function api_get_user_info_from_entity(
1606
    User $user,
1607
    $checkIfUserOnline = false,
1608
    $showPassword = false,
1609
    $loadExtraData = false,
1610
    $loadOnlyVisibleExtraData = false,
1611
    $loadAvatars = true,
1612
    $loadCertificate = false
1613
) {
1614
    if (!$user instanceof UserInterface) {
1615
        return false;
1616
    }
1617
1618
    // Make sure user_id is safe
1619
    $user_id = (int) $user->getId();
1620
1621
    if (empty($user_id)) {
1622
        $userFromSession = Session::read('_user');
1623
1624
        if (isset($userFromSession) && !empty($userFromSession)) {
1625
            return $userFromSession;
1626
        }
1627
1628
        return false;
1629
    }
1630
1631
    $result = [];
1632
    $result['user_is_online_in_chat'] = 0;
1633
    if ($checkIfUserOnline) {
1634
        $use_status_in_platform = user_is_online($user_id);
1635
        $result['user_is_online'] = $use_status_in_platform;
1636
        $user_online_in_chat = 0;
1637
        if ($use_status_in_platform) {
1638
            $user_status = UserManager::get_extra_user_data_by_field(
1639
                $user_id,
1640
                'user_chat_status',
1641
                false,
1642
                true
1643
            );
1644
            if (1 == (int) $user_status['user_chat_status']) {
1645
                $user_online_in_chat = 1;
1646
            }
1647
        }
1648
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1649
    }
1650
1651
    if ($loadExtraData) {
1652
        $fieldValue = new ExtraFieldValue('user');
1653
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1654
            $user_id,
1655
            $loadOnlyVisibleExtraData
1656
        );
1657
    }
1658
1659
    $result['username'] = $user->getUsername();
1660
    $result['status'] = $user->getStatus();
1661
    $result['firstname'] = $user->getFirstname();
1662
    $result['lastname'] = $user->getLastname();
1663
    $result['email'] = $result['mail'] = $user->getEmail();
1664
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1665
    $result['complete_name_with_username'] = $result['complete_name'];
1666
1667
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1668
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1669
    }
1670
1671
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1672
    if (!empty($result['email'])) {
1673
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1674
        if ($showEmail) {
1675
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1676
        }
1677
    } else {
1678
        $result['complete_name_with_email'] = $result['complete_name'];
1679
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1680
    }
1681
1682
    // Kept for historical reasons
1683
    $result['firstName'] = $result['firstname'];
1684
    $result['lastName'] = $result['lastname'];
1685
1686
    $attributes = [
1687
        'picture_uri',
1688
        'last_login',
1689
        'user_is_online',
1690
    ];
1691
1692
    $result['phone'] = $user->getPhone();
1693
    $result['address'] = $user->getAddress();
1694
    $result['official_code'] = $user->getOfficialCode();
1695
    $result['active'] = $user->getActive();
1696
    $result['auth_source'] = $user->getAuthSource();
1697
    $result['language'] = $user->getLanguage();
1698
    $result['creator_id'] = $user->getCreatorId();
1699
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1700
    $result['hr_dept_id'] = $user->getHrDeptId();
1701
    $result['expiration_date'] = '';
1702
    if ($user->getExpirationDate()) {
1703
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1704
    }
1705
1706
    $result['last_login'] = null;
1707
    if ($user->getLastLogin()) {
1708
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1709
    }
1710
1711
    $result['competences'] = $user->getCompetences();
1712
    $result['diplomas'] = $user->getDiplomas();
1713
    $result['teach'] = $user->getTeach();
1714
    $result['openarea'] = $user->getOpenarea();
1715
    $user_id = (int) $user->getId();
1716
1717
    // Maintain the user_id index for backwards compatibility
1718
    $result['user_id'] = $result['id'] = $user_id;
1719
1720
    if ($loadCertificate) {
1721
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1722
        $result['has_certificates'] = 0;
1723
        if (!empty($hasCertificates)) {
1724
            $result['has_certificates'] = 1;
1725
        }
1726
    }
1727
1728
    $result['icon_status'] = '';
1729
    $result['icon_status_medium'] = '';
1730
    $result['is_admin'] = UserManager::is_admin($user_id);
1731
1732
    // Getting user avatar.
1733
    if ($loadAvatars) {
1734
        $result['avatar'] = '';
1735
        $result['avatar_no_query'] = '';
1736
        $result['avatar_small'] = '';
1737
        $result['avatar_medium'] = '';
1738
1739
        /*if (!isset($user['avatar'])) {
1740
            $originalFile = UserManager::getUserPicture(
1741
                $user_id,
1742
                USER_IMAGE_SIZE_ORIGINAL,
1743
                null,
1744
                $result
1745
            );
1746
            $result['avatar'] = $originalFile;
1747
            $avatarString = explode('?', $result['avatar']);
1748
            $result['avatar_no_query'] = reset($avatarString);
1749
        } else {
1750
            $result['avatar'] = $user['avatar'];
1751
            $avatarString = explode('?', $user['avatar']);
1752
            $result['avatar_no_query'] = reset($avatarString);
1753
        }
1754
1755
        if (!isset($user['avatar_small'])) {
1756
            $smallFile = UserManager::getUserPicture(
1757
                $user_id,
1758
                USER_IMAGE_SIZE_SMALL,
1759
                null,
1760
                $result
1761
            );
1762
            $result['avatar_small'] = $smallFile;
1763
        } else {
1764
            $result['avatar_small'] = $user['avatar_small'];
1765
        }
1766
1767
        if (!isset($user['avatar_medium'])) {
1768
            $mediumFile = UserManager::getUserPicture(
1769
                $user_id,
1770
                USER_IMAGE_SIZE_MEDIUM,
1771
                null,
1772
                $result
1773
            );
1774
            $result['avatar_medium'] = $mediumFile;
1775
        } else {
1776
            $result['avatar_medium'] = $user['avatar_medium'];
1777
        }*/
1778
1779
        //$urlImg = api_get_path(WEB_IMG_PATH);
1780
        $urlImg = '/';
1781
        $iconStatus = '';
1782
        $iconStatusMedium = '';
1783
1784
        switch ($user->getStatus()) {
1785
            case STUDENT:
1786
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1787
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1788
                } else {
1789
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1790
                }
1791
                break;
1792
            case COURSEMANAGER:
1793
                if ($result['is_admin']) {
1794
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1795
                } else {
1796
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1797
                }
1798
                break;
1799
            case STUDENT_BOSS:
1800
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1801
                break;
1802
        }
1803
1804
        if (!empty($iconStatus)) {
1805
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1806
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1807
        }
1808
1809
        $result['icon_status'] = $iconStatus;
1810
        $result['icon_status_medium'] = $iconStatusMedium;
1811
    }
1812
1813
    if (isset($result['user_is_online'])) {
1814
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1815
    }
1816
    if (isset($result['user_is_online_in_chat'])) {
1817
        $result['user_is_online_in_chat'] = (int) $result['user_is_online_in_chat'];
1818
    }
1819
1820
    $result['password'] = '';
1821
    if ($showPassword) {
1822
        $result['password'] = $user->getPassword();
1823
    }
1824
1825
    if (isset($result['profile_completed'])) {
1826
        $result['profile_completed'] = $result['profile_completed'];
1827
    }
1828
1829
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1830
1831
    // Send message link
1832
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1833
    $result['complete_name_with_message_link'] = Display::url(
1834
        $result['complete_name_with_username'],
1835
        $sendMessage,
1836
        ['class' => 'ajax']
1837
    );
1838
1839
    if (isset($result['extra'])) {
1840
        $result['extra'] = $result['extra'];
1841
    }
1842
1843
    return $result;
1844
}
1845
1846
function api_get_lp_entity(int $id): ?CLp
1847
{
1848
    return Database::getManager()->getRepository(CLp::class)->find($id);
1849
}
1850
1851
function api_get_user_entity(int $userId = 0): ?User
1852
{
1853
    $userId = $userId ?: api_get_user_id();
1854
    $repo = UserManager::getRepository();
1855
1856
    /** @var User $user */
1857
    $user = $repo->find($userId);
1858
1859
    return $user;
1860
}
1861
1862
function api_get_current_user(): ?User
1863
{
1864
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1865
    if (false === $isLoggedIn) {
1866
        return null;
1867
    }
1868
1869
    $token = Container::$container->get('security.token_storage')->getToken();
1870
1871
    if (null !== $token) {
1872
        return $token->getUser();
1873
    }
1874
1875
    return null;
1876
}
1877
1878
/**
1879
 * Finds all the information about a user from username instead of user id.
1880
 *
1881
 * @param string $username
1882
 *
1883
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1884
 *
1885
 * @author Yannick Warnier <[email protected]>
1886
 */
1887
function api_get_user_info_from_username($username)
1888
{
1889
    if (empty($username)) {
1890
        return false;
1891
    }
1892
    $username = trim($username);
1893
1894
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1895
            WHERE username='".Database::escape_string($username)."'";
1896
    $result = Database::query($sql);
1897
    if (Database::num_rows($result) > 0) {
1898
        $resultArray = Database::fetch_array($result);
1899
1900
        return _api_format_user($resultArray);
1901
    }
1902
1903
    return false;
1904
}
1905
1906
/**
1907
 * Get first user with an email.
1908
 *
1909
 * @param string $email
1910
 *
1911
 * @return array|bool
1912
 */
1913
function api_get_user_info_from_email($email = '')
1914
{
1915
    if (empty($email)) {
1916
        return false;
1917
    }
1918
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1919
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1920
    $result = Database::query($sql);
1921
    if (Database::num_rows($result) > 0) {
1922
        $resultArray = Database::fetch_array($result);
1923
1924
        return _api_format_user($resultArray);
1925
    }
1926
1927
    return false;
1928
}
1929
1930
/**
1931
 * @return string
1932
 */
1933
function api_get_course_id()
1934
{
1935
    return Session::read('_cid', null);
1936
}
1937
1938
/**
1939
 * Returns the current course id (integer).
1940
 *
1941
 * @param string $code Optional course code
1942
 *
1943
 * @return int
1944
 */
1945
function api_get_course_int_id($code = null)
1946
{
1947
    if (!empty($code)) {
1948
        $code = Database::escape_string($code);
1949
        $row = Database::select(
1950
            'id',
1951
            Database::get_main_table(TABLE_MAIN_COURSE),
1952
            ['where' => ['code = ?' => [$code]]],
1953
            'first'
1954
        );
1955
1956
        if (is_array($row) && isset($row['id'])) {
1957
            return $row['id'];
1958
        } else {
1959
            return false;
1960
        }
1961
    }
1962
1963
    return Session::read('_real_cid', 0);
1964
}
1965
1966
/**
1967
 * Returns the current course directory.
1968
 *
1969
 * This function relies on api_get_course_info()
1970
 *
1971
 * @param string    The course code - optional (takes it from session if not given)
1972
 *
1973
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1974
 *
1975
 * @author Yannick Warnier <[email protected]>
1976
 */
1977
function api_get_course_path($course_code = null)
1978
{
1979
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1980
1981
    return $info['path'];
1982
}
1983
1984
/**
1985
 * Gets a course setting from the current course_setting table. Try always using integer values.
1986
 *
1987
 * @param string $settingName The name of the setting we want from the table
1988
 * @param array  $courseInfo
1989
 * @param bool   $force       force checking the value in the database
1990
 *
1991
 * @return mixed The value of that setting in that table. Return -1 if not found.
1992
 */
1993
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1994
{
1995
    if (empty($courseInfo)) {
1996
        $courseInfo = api_get_course_info();
1997
    }
1998
1999
    if (empty($courseInfo) || empty($settingName)) {
2000
        return -1;
2001
    }
2002
2003
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2004
2005
    if (empty($courseId)) {
2006
        return -1;
2007
    }
2008
2009
    static $courseSettingInfo = [];
2010
2011
    if ($force) {
2012
        $courseSettingInfo = [];
2013
    }
2014
2015
    if (!isset($courseSettingInfo[$courseId])) {
2016
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2017
        $settingName = Database::escape_string($settingName);
2018
2019
        $sql = "SELECT variable, value FROM $table
2020
                WHERE c_id = $courseId ";
2021
        $res = Database::query($sql);
2022
        if (Database::num_rows($res) > 0) {
2023
            $result = Database::store_result($res, 'ASSOC');
2024
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2025
2026
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2027
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2028
                if (!is_null($value)) {
2029
                    $result = explode(',', $value);
2030
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2031
                }
2032
            }
2033
        }
2034
    }
2035
2036
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2037
        return $courseSettingInfo[$courseId][$settingName];
2038
    }
2039
2040
    return -1;
2041
}
2042
2043
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2044
{
2045
    $value = api_get_course_setting($settingName, $courseInfo, true);
2046
2047
    if (-1 === $value) {
2048
        // Check global settings
2049
        $value = api_get_plugin_setting($plugin, $settingName);
2050
        if ('true' === $value) {
2051
            return 1;
2052
        }
2053
        if ('false' === $value) {
2054
            return 0;
2055
        }
2056
        if (null === $value) {
2057
            return -1;
2058
        }
2059
    }
2060
2061
    return $value;
2062
}
2063
2064
/**
2065
 * Gets an anonymous user ID.
2066
 *
2067
 * For some tools that need tracking, like the learnpath tool, it is necessary
2068
 * to have a usable user-id to enable some kind of tracking, even if not
2069
 * perfect. An anonymous ID is taken from the users table by looking for a
2070
 * status of "6" (anonymous).
2071
 *
2072
 * @return int User ID of the anonymous user, or O if no anonymous user found
2073
 */
2074
function api_get_anonymous_id()
2075
{
2076
    // Find if another anon is connected now
2077
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2078
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2079
    $ip = Database::escape_string(api_get_real_ip());
2080
    $max = (int) api_get_configuration_value('max_anonymous_users');
2081
    if ($max >= 2) {
2082
        $sql = "SELECT * FROM $table as TEL
2083
                JOIN $tableU as U
2084
                ON U.id = TEL.login_user_id
2085
                WHERE TEL.user_ip = '$ip'
2086
                    AND U.status = ".ANONYMOUS."
2087
                    AND U.id != 2 ";
2088
2089
        $result = Database::query($sql);
2090
        if (empty(Database::num_rows($result))) {
2091
            $login = uniqid('anon_');
2092
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2093
            if (count($anonList) >= $max) {
2094
                foreach ($anonList as $userToDelete) {
2095
                    UserManager::delete_user($userToDelete['user_id']);
2096
                    break;
2097
                }
2098
            }
2099
2100
            return UserManager::create_user(
2101
                $login,
2102
                'anon',
2103
                ANONYMOUS,
2104
                ' anonymous@localhost',
2105
                $login,
2106
                $login
2107
            );
2108
        } else {
2109
            $row = Database::fetch_array($result, 'ASSOC');
2110
2111
            return $row['id'];
2112
        }
2113
    }
2114
2115
    $table = Database::get_main_table(TABLE_MAIN_USER);
2116
    $sql = "SELECT id
2117
            FROM $table
2118
            WHERE status = ".ANONYMOUS." ";
2119
    $res = Database::query($sql);
2120
    if (Database::num_rows($res) > 0) {
2121
        $row = Database::fetch_array($res, 'ASSOC');
2122
2123
        return $row['id'];
2124
    }
2125
2126
    // No anonymous user was found.
2127
    return 0;
2128
}
2129
2130
/**
2131
 * @param int $courseId
2132
 * @param int $sessionId
2133
 * @param int $groupId
2134
 *
2135
 * @return string
2136
 */
2137
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2138
{
2139
    $courseId = !empty($courseId) ? (int) $courseId : 0;
2140
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2141
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2142
2143
    $url = 'cid='.$courseId;
2144
    $url .= '&sid='.$sessionId;
2145
    $url .= '&gid='.$groupId;
2146
2147
    return $url;
2148
}
2149
2150
/**
2151
 * Returns the current course url part including session, group, and gradebook params.
2152
 *
2153
 * @param bool   $addSessionId
2154
 * @param bool   $addGroupId
2155
 * @param string $origin
2156
 *
2157
 * @return string Course & session references to add to a URL
2158
 */
2159
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2160
{
2161
    $courseId = api_get_course_int_id();
2162
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2163
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2164
2165
    if ($addSessionId) {
2166
        if (!empty($url)) {
2167
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2168
        }
2169
    }
2170
2171
    if ($addGroupId) {
2172
        if (!empty($url)) {
2173
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2174
        }
2175
    }
2176
2177
    if (!empty($url)) {
2178
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2179
        $url .= '&origin='.$origin;
2180
    }
2181
2182
    return $url;
2183
}
2184
2185
/**
2186
 * Get if we visited a gradebook page.
2187
 *
2188
 * @return bool
2189
 */
2190
function api_is_in_gradebook()
2191
{
2192
    return Session::read('in_gradebook', false);
2193
}
2194
2195
/**
2196
 * Set that we are in a page inside a gradebook.
2197
 */
2198
function api_set_in_gradebook()
2199
{
2200
    Session::write('in_gradebook', true);
2201
}
2202
2203
/**
2204
 * Remove gradebook session.
2205
 */
2206
function api_remove_in_gradebook()
2207
{
2208
    Session::erase('in_gradebook');
2209
}
2210
2211
/**
2212
 * Returns the current course info array see api_format_course_array()
2213
 * If the course_code is given, the returned array gives info about that
2214
 * particular course, if none given it gets the course info from the session.
2215
 *
2216
 * @param string $courseCode
2217
 *
2218
 * @return array
2219
 */
2220
function api_get_course_info($courseCode = null)
2221
{
2222
    if (!empty($courseCode)) {
2223
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2224
2225
        return api_format_course_array($course);
2226
    }
2227
2228
    /*$course_code = Database::escape_string($course_code);
2229
    $courseId = api_get_course_int_id($course_code);
2230
    if (empty($courseId)) {
2231
        return [];
2232
    }
2233
2234
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2235
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2236
    $sql = "SELECT
2237
                course.*,
2238
                course_category.code faCode,
2239
                course_category.name faName
2240
            FROM $course_table
2241
            LEFT JOIN $course_cat_table
2242
            ON course.category_code = course_category.code
2243
            WHERE course.id = $courseId";
2244
    $result = Database::query($sql);
2245
    $courseInfo = [];
2246
    if (Database::num_rows($result) > 0) {
2247
        $data = Database::fetch_array($result);
2248
        $courseInfo = api_format_course_array($data);
2249
    }
2250
2251
    return $courseInfo;*/
2252
2253
    $course = Session::read('_course');
2254
    if ('-1' == $course) {
2255
        $course = [];
2256
    }
2257
2258
    return $course;
2259
}
2260
2261
/**
2262
 * @param int $courseId
2263
 */
2264
function api_get_course_entity($courseId = 0): ?Course
2265
{
2266
    if (empty($courseId)) {
2267
        $courseId = api_get_course_int_id();
2268
    }
2269
2270
    return Container::getCourseRepository()->find($courseId);
2271
}
2272
2273
/**
2274
 * @param int $id
2275
 */
2276
function api_get_session_entity($id = 0): ?SessionEntity
2277
{
2278
    if (empty($id)) {
2279
        $id = api_get_session_id();
2280
    }
2281
2282
    if (empty($id)) {
2283
        return null;
2284
    }
2285
2286
    return Container::getSessionRepository()->find($id);
2287
}
2288
2289
/**
2290
 * @param int $id
2291
 */
2292
function api_get_group_entity($id = 0): ?CGroup
2293
{
2294
    if (empty($id)) {
2295
        $id = api_get_group_id();
2296
    }
2297
2298
    return Container::getGroupRepository()->find($id);
2299
}
2300
2301
/**
2302
 * @param int $id
2303
 */
2304
function api_get_url_entity($id = 0): ?AccessUrl
2305
{
2306
    if (empty($id)) {
2307
        $id = api_get_current_access_url_id();
2308
    }
2309
2310
    return Container::getAccessUrlRepository()->find($id);
2311
}
2312
2313
/**
2314
 * Returns the current course info array.
2315
2316
 * Now if the course_code is given, the returned array gives info about that
2317
 * particular course, not specially the current one.
2318
 *
2319
 * @param int $id Numeric ID of the course
2320
 *
2321
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2322
 */
2323
function api_get_course_info_by_id($id = 0)
2324
{
2325
    $id = (int) $id;
2326
    if (empty($id)) {
2327
        $course = Session::read('_course', []);
2328
2329
        return $course;
2330
    }
2331
2332
    $course = Container::getCourseRepository()->find($id);
2333
    if (empty($course)) {
2334
        return [];
2335
    }
2336
2337
    return api_format_course_array($course);
2338
}
2339
2340
/**
2341
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2342
 * to switch from 'code' to 'id' in the array.
2343
 *
2344
 * @return array
2345
 *
2346
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2347
 */
2348
function api_format_course_array(Course $course = null)
2349
{
2350
    if (empty($course)) {
2351
        return [];
2352
    }
2353
2354
    $courseData = [];
2355
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2356
2357
    // Added
2358
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2359
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2360
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2361
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2362
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2363
    $courseData['titular'] = $course->getTutorName();
2364
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2365
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2366
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2367
2368
    $courseData['visibility'] = $course->getVisibility();
2369
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2370
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2371
    $courseData['activate_legal'] = $course->getActivateLegal();
2372
    $courseData['legal'] = $course->getLegal();
2373
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2374
2375
    //$coursePath = api_get_path(WEB_COURSE_PATH);
2376
    $coursePath = '/course/';
2377
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2378
2379
    // Course password
2380
    $courseData['registration_code'] = $course->getRegistrationCode();
2381
    $courseData['disk_quota'] = $course->getDiskQuota();
2382
    $courseData['course_public_url'] = $webCourseHome;
2383
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2384
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2385
    $courseData['entity'] = $course;
2386
2387
    $image = Display::return_icon(
2388
        'course.png',
2389
        null,
2390
        null,
2391
        ICON_SIZE_BIG,
2392
        null,
2393
        true,
2394
        false
2395
    );
2396
2397
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2398
    if (!empty($illustration)) {
2399
        $image = $illustration;
2400
    }
2401
2402
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2403
2404
    // Course large image
2405
    /*$courseData['course_image_large_source'] = '';
2406
    if (file_exists($courseSys.'/course-pic.png')) {
2407
        $url_image = $webCourseHome.'/course-pic.png';
2408
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2409
    } else {
2410
        $url_image = Display::return_icon(
2411
            'session_default.png',
2412
            null,
2413
            null,
2414
            null,
2415
            null,
2416
            true,
2417
            true
2418
        );
2419
    }*/
2420
2421
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2422
2423
    return $courseData;
2424
}
2425
2426
/**
2427
 * Returns a difficult to guess password.
2428
 *
2429
 * @param int $length the length of the password
2430
 *
2431
 * @return string the generated password
2432
 */
2433
function api_generate_password($length = 8)
2434
{
2435
    if ($length < 2) {
2436
        $length = 2;
2437
    }
2438
2439
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2440
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2441
    $minNumbers = 2;
2442
    $length = $length - $minNumbers;
2443
    $minLowerCase = round($length / 2);
2444
    $minUpperCase = $length - $minLowerCase;
2445
2446
    $password = '';
2447
    $passwordRequirements = api_get_configuration_value('password_requirements');
2448
2449
    $factory = new RandomLib\Factory();
2450
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2451
2452
    if (!empty($passwordRequirements)) {
2453
        $length = $passwordRequirements['min']['length'];
2454
        $minNumbers = $passwordRequirements['min']['numeric'];
2455
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2456
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2457
2458
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2459
        // Add the rest to fill the length requirement
2460
        if ($rest > 0) {
2461
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2462
        }
2463
    }
2464
2465
    // Min digits default 2
2466
    for ($i = 0; $i < $minNumbers; $i++) {
2467
        $password .= $generator->generateInt(2, 9);
2468
    }
2469
2470
    // Min lowercase
2471
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2472
2473
    // Min uppercase
2474
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2475
    $password = str_shuffle($password);
2476
2477
    return $password;
2478
}
2479
2480
/**
2481
 * Checks a password to see wether it is OK to use.
2482
 *
2483
 * @param string $password
2484
 *
2485
 * @return bool if the password is acceptable, false otherwise
2486
 *              Notes about what a password "OK to use" is:
2487
 *              1. The password should be at least 5 characters long.
2488
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2489
 *              3. The password should contain at least 3 letters.
2490
 *              4. It should contain at least 2 digits.
2491
 *              Settings will change if the configuration value is set: password_requirements
2492
 */
2493
function api_check_password($password)
2494
{
2495
    $passwordRequirements = Security::getPasswordRequirements();
2496
2497
    $minLength = $passwordRequirements['min']['length'];
2498
    $minNumbers = $passwordRequirements['min']['numeric'];
2499
    // Optional
2500
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2501
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2502
2503
    $minLetters = $minLowerCase + $minUpperCase;
2504
    $passwordLength = api_strlen($password);
2505
2506
    $conditions = [
2507
        'min_length' => $passwordLength >= $minLength,
2508
    ];
2509
2510
    $digits = 0;
2511
    $lowerCase = 0;
2512
    $upperCase = 0;
2513
2514
    for ($i = 0; $i < $passwordLength; $i++) {
2515
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2516
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2517
            $upperCase++;
2518
        }
2519
2520
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2521
            $lowerCase++;
2522
        }
2523
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2524
            $digits++;
2525
        }
2526
    }
2527
2528
    // Min number of digits
2529
    $conditions['min_numeric'] = $digits >= $minNumbers;
2530
2531
    if (!empty($minUpperCase)) {
2532
        // Uppercase
2533
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2534
    }
2535
2536
    if (!empty($minLowerCase)) {
2537
        // Lowercase
2538
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2539
    }
2540
2541
    // Min letters
2542
    $letters = $upperCase + $lowerCase;
2543
    $conditions['min_letters'] = $letters >= $minLetters;
2544
2545
    $isPasswordOk = true;
2546
    foreach ($conditions as $condition) {
2547
        if (false === $condition) {
2548
            $isPasswordOk = false;
2549
            break;
2550
        }
2551
    }
2552
2553
    if (false === $isPasswordOk) {
2554
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2555
        $output .= Security::getPasswordRequirementsToString($conditions);
2556
2557
        Display::addFlash(Display::return_message($output, 'warning', false));
2558
    }
2559
2560
    return $isPasswordOk;
2561
}
2562
2563
/**
2564
 * Returns the status string corresponding to the status code.
2565
 *
2566
 * @author Noel Dieschburg
2567
 *
2568
 * @param the int status code
2569
 *
2570
 * @return string
2571
 */
2572
function get_status_from_code($status_code)
2573
{
2574
    switch ($status_code) {
2575
        case STUDENT:
2576
            return get_lang('Student', '');
2577
        case COURSEMANAGER:
2578
            return get_lang('Teacher', '');
2579
        case SESSIONADMIN:
2580
            return get_lang('SessionsAdmin', '');
2581
        case DRH:
2582
            return get_lang('Drh', '');
2583
    }
2584
}
2585
2586
/**
2587
 * Gets the current Chamilo (not PHP/cookie) session ID.
2588
 *
2589
 * @return int O if no active session, the session ID otherwise
2590
 */
2591
function api_get_session_id()
2592
{
2593
    return (int) Session::read('sid', 0);
2594
}
2595
2596
/**
2597
 * Gets the current Chamilo (not social network) group ID.
2598
 *
2599
 * @return int O if no active session, the session ID otherwise
2600
 */
2601
function api_get_group_id()
2602
{
2603
    return Session::read('gid', 0);
2604
}
2605
2606
/**
2607
 * Gets the current or given session name.
2608
 *
2609
 * @param   int     Session ID (optional)
2610
 *
2611
 * @return string The session name, or null if not found
2612
 */
2613
function api_get_session_name($session_id = 0)
2614
{
2615
    if (empty($session_id)) {
2616
        $session_id = api_get_session_id();
2617
        if (empty($session_id)) {
2618
            return null;
2619
        }
2620
    }
2621
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2622
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2623
    $r = Database::query($s);
2624
    $c = Database::num_rows($r);
2625
    if ($c > 0) {
2626
        //technically, there can be only one, but anyway we take the first
2627
        $rec = Database::fetch_array($r);
2628
2629
        return $rec['name'];
2630
    }
2631
2632
    return null;
2633
}
2634
2635
/**
2636
 * Gets the session info by id.
2637
 *
2638
 * @param int $id Session ID
2639
 *
2640
 * @return array information of the session
2641
 */
2642
function api_get_session_info($id)
2643
{
2644
    return SessionManager::fetch($id);
2645
}
2646
2647
/**
2648
 * Gets the session visibility by session id.
2649
 *
2650
 * @param int  $session_id
2651
 * @param int  $courseId
2652
 * @param bool $ignore_visibility_for_admins
2653
 *
2654
 * @return int
2655
 *             0 = session still available,
2656
 *             SESSION_VISIBLE_READ_ONLY = 1,
2657
 *             SESSION_VISIBLE = 2,
2658
 *             SESSION_INVISIBLE = 3
2659
 */
2660
function api_get_session_visibility(
2661
    $session_id,
2662
    $courseId = null,
2663
    $ignore_visibility_for_admins = true
2664
) {
2665
    if (api_is_platform_admin()) {
2666
        if ($ignore_visibility_for_admins) {
2667
            return SESSION_AVAILABLE;
2668
        }
2669
    }
2670
2671
    $now = time();
2672
    if (empty($session_id)) {
2673
        return 0; // Means that the session is still available.
2674
    }
2675
2676
    $session_id = (int) $session_id;
2677
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2678
2679
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2680
2681
    if (Database::num_rows($result) <= 0) {
2682
        return SESSION_INVISIBLE;
2683
    }
2684
2685
    $row = Database::fetch_array($result, 'ASSOC');
2686
    $visibility = $row['visibility'];
2687
2688
    // I don't care the session visibility.
2689
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2690
        // Session duration per student.
2691
        if (isset($row['duration']) && !empty($row['duration'])) {
2692
            $duration = $row['duration'] * 24 * 60 * 60;
2693
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2694
2695
            // If there is a session duration but there is no previous
2696
            // access by the user, then the session is still available
2697
            if (0 == count($courseAccess)) {
2698
                return SESSION_AVAILABLE;
2699
            }
2700
2701
            $currentTime = time();
2702
            $firstAccess = isset($courseAccess['login_course_date'])
2703
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2704
                : 0;
2705
            $userDurationData = SessionManager::getUserSession(
2706
                api_get_user_id(),
2707
                $session_id
2708
            );
2709
            $userDuration = isset($userDurationData['duration'])
2710
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2711
                : 0;
2712
2713
            $totalDuration = $firstAccess + $duration + $userDuration;
2714
2715
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2716
        }
2717
2718
        return SESSION_AVAILABLE;
2719
    }
2720
2721
    // If start date was set.
2722
    if (!empty($row['access_start_date'])) {
2723
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2724
    }
2725
2726
    // If the end date was set.
2727
    if (!empty($row['access_end_date'])) {
2728
        // Only if date_start said that it was ok
2729
        if (SESSION_AVAILABLE === $visibility) {
2730
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2731
                ? SESSION_AVAILABLE // Date still available
2732
                : $row['visibility']; // Session ends
2733
        }
2734
    }
2735
2736
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2737
    $isCoach = api_is_coach($session_id, $courseId);
2738
2739
    if ($isCoach) {
2740
        // Test start date.
2741
        if (!empty($row['coach_access_start_date'])) {
2742
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2743
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2744
        }
2745
2746
        // Test end date.
2747
        if (!empty($row['coach_access_end_date'])) {
2748
            if (SESSION_AVAILABLE === $visibility) {
2749
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2750
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2751
            }
2752
        }
2753
    }
2754
2755
    return $visibility;
2756
}
2757
2758
/**
2759
 * This function returns a (star) session icon if the session is not null and
2760
 * the user is not a student.
2761
 *
2762
 * @param int $sessionId
2763
 * @param int $statusId  User status id - if 5 (student), will return empty
2764
 *
2765
 * @return string Session icon
2766
 */
2767
function api_get_session_image($sessionId, $statusId)
2768
{
2769
    $sessionId = (int) $sessionId;
2770
    $image = '';
2771
    if (STUDENT != $statusId) {
2772
        // Check whether is not a student
2773
        if ($sessionId > 0) {
2774
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2775
                'star.png',
2776
                get_lang('Session-specific resource'),
2777
                ['align' => 'absmiddle'],
2778
                ICON_SIZE_SMALL
2779
            );
2780
        }
2781
    }
2782
2783
    return $image;
2784
}
2785
2786
/**
2787
 * This function add an additional condition according to the session of the course.
2788
 *
2789
 * @param int    $session_id        session id
2790
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2791
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2792
 *                                  false for strict session condition
2793
 * @param string $session_field
2794
 *
2795
 * @return string condition of the session
2796
 */
2797
function api_get_session_condition(
2798
    $session_id,
2799
    $and = true,
2800
    $with_base_content = false,
2801
    $session_field = 'session_id'
2802
) {
2803
    $session_id = (int) $session_id;
2804
2805
    if (empty($session_field)) {
2806
        $session_field = 'session_id';
2807
    }
2808
    // Condition to show resources by session
2809
    $condition_add = $and ? ' AND ' : ' WHERE ';
2810
2811
    if ($with_base_content) {
2812
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2813
    } else {
2814
        if (empty($session_id)) {
2815
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2816
        } else {
2817
            $condition_session = $condition_add." $session_field = $session_id ";
2818
        }
2819
    }
2820
2821
    return $condition_session;
2822
}
2823
2824
/**
2825
 * Returns the value of a setting from the web-adjustable admin config settings.
2826
 *
2827
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2828
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2829
 * instead of
2830
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2831
 *
2832
 * @param string $variable The variable name
2833
 *
2834
 * @return string
2835
 */
2836
function api_get_setting($variable)
2837
{
2838
    $settingsManager = Container::getSettingsManager();
2839
    if (empty($settingsManager)) {
2840
        return '';
2841
    }
2842
    $variable = trim($variable);
2843
2844
    switch ($variable) {
2845
        /*case 'header_extra_content':
2846
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2847
            if (file_exists($filename)) {
2848
                $value = file_get_contents($filename);
2849
2850
                return $value;
2851
            } else {
2852
                return '';
2853
            }
2854
            break;
2855
        case 'footer_extra_content':
2856
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2857
            if (file_exists($filename)) {
2858
                $value = file_get_contents($filename);
2859
2860
                return $value;
2861
            } else {
2862
                return '';
2863
            }
2864
            break;*/
2865
        case 'server_type':
2866
            $test = ['dev', 'test'];
2867
            $environment = Container::getEnvironment();
2868
            if (in_array($environment, $test)) {
2869
                return 'test';
2870
            }
2871
2872
            return 'prod';
2873
        case 'stylesheets':
2874
            $variable = 'platform.theme';
2875
        // deprecated settings
2876
        // no break
2877
        case 'openid_authentication':
2878
        case 'service_ppt2lp':
2879
        case 'formLogin_hide_unhide_label':
2880
            return false;
2881
            break;
2882
        case 'tool_visible_by_default_at_creation':
2883
            $values = $settingsManager->getSetting($variable);
2884
            $newResult = [];
2885
            foreach ($values as $parameter) {
2886
                $newResult[$parameter] = 'true';
2887
            }
2888
2889
            return $newResult;
2890
            break;
2891
        default:
2892
            return $settingsManager->getSetting($variable);
2893
            break;
2894
    }
2895
}
2896
2897
/**
2898
 * @param string $variable
2899
 * @param string $option
2900
 *
2901
 * @return bool
2902
 */
2903
function api_get_setting_in_list($variable, $option)
2904
{
2905
    $value = api_get_setting($variable);
2906
2907
    return in_array($option, $value);
2908
}
2909
2910
/**
2911
 * @param string $plugin
2912
 * @param string $variable
2913
 *
2914
 * @return string
2915
 */
2916
function api_get_plugin_setting($plugin, $variable)
2917
{
2918
    $variableName = $plugin.'_'.$variable;
2919
    //$result = api_get_setting($variableName);
2920
    $params = [
2921
        'category = ? AND subkey = ? AND variable = ?' => [
2922
            'Plugins',
2923
            $plugin,
2924
            $variableName,
2925
        ],
2926
    ];
2927
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2928
    $result = Database::select(
2929
        'selected_value',
2930
        $table,
2931
        ['where' => $params],
2932
        'one'
2933
    );
2934
    if ($result) {
2935
        $value = $result['selected_value'];
2936
        $serializedValue = @unserialize($result['selected_value'], []);
2937
        if (false !== $serializedValue) {
2938
            $value = $serializedValue;
2939
        }
2940
2941
        return $value;
2942
    }
2943
2944
    return null;
2945
    /// Old code
2946
2947
    $variableName = $plugin.'_'.$variable;
2948
    $result = api_get_setting($variableName);
2949
2950
    if (isset($result[$plugin])) {
2951
        $value = $result[$plugin];
2952
2953
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2954
2955
        if (false !== $unserialized) {
2956
            $value = $unserialized;
2957
        }
2958
2959
        return $value;
2960
    }
2961
2962
    return null;
2963
}
2964
2965
/**
2966
 * Returns the value of a setting from the web-adjustable admin config settings.
2967
 */
2968
function api_get_settings_params($params)
2969
{
2970
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2971
    $result = Database::select('*', $table, ['where' => $params]);
2972
2973
    return $result;
2974
}
2975
2976
/**
2977
 * @param array $params example: [id = ? => '1']
2978
 *
2979
 * @return array
2980
 */
2981
function api_get_settings_params_simple($params)
2982
{
2983
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2984
    $result = Database::select('*', $table, ['where' => $params], 'one');
2985
2986
    return $result;
2987
}
2988
2989
/**
2990
 * Returns the value of a setting from the web-adjustable admin config settings.
2991
 */
2992
function api_delete_settings_params($params)
2993
{
2994
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2995
    $result = Database::delete($table, $params);
2996
2997
    return $result;
2998
}
2999
3000
/**
3001
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3002
 *
3003
 * @return string Escaped version of $_SERVER['PHP_SELF']
3004
 */
3005
function api_get_self()
3006
{
3007
    return htmlentities($_SERVER['PHP_SELF']);
3008
}
3009
3010
/* USER PERMISSIONS */
3011
3012
/**
3013
 * Checks whether current user is a platform administrator.
3014
 *
3015
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3016
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3017
 *
3018
 * @return bool true if the user has platform admin rights,
3019
 *              false otherwise
3020
 *
3021
 * @see usermanager::is_admin(user_id) for a user-id specific function
3022
 */
3023
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3024
{
3025
    $currentUser = api_get_current_user();
3026
3027
    if (null === $currentUser) {
3028
        return false;
3029
    }
3030
3031
    $isAdmin = Session::read('is_platformAdmin');
3032
    if ($isAdmin) {
3033
        return true;
3034
    }
3035
    $user = api_get_user_info();
3036
3037
    return
3038
        isset($user['status']) &&
3039
        (
3040
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3041
            ($allowDrh && DRH == $user['status'])
3042
        );
3043
}
3044
3045
/**
3046
 * Checks whether the user given as user id is in the admin table.
3047
 *
3048
 * @param int $user_id If none provided, will use current user
3049
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3050
 *
3051
 * @return bool True if the user is admin, false otherwise
3052
 */
3053
function api_is_platform_admin_by_id($user_id = null, $url = null)
3054
{
3055
    $user_id = (int) $user_id;
3056
    if (empty($user_id)) {
3057
        $user_id = api_get_user_id();
3058
    }
3059
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3060
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3061
    $res = Database::query($sql);
3062
    $is_admin = 1 === Database::num_rows($res);
3063
    if (!$is_admin || !isset($url)) {
3064
        return $is_admin;
3065
    }
3066
    // We get here only if $url is set
3067
    $url = (int) $url;
3068
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3069
    $sql = "SELECT * FROM $url_user_table
3070
            WHERE access_url_id = $url AND user_id = $user_id";
3071
    $res = Database::query($sql);
3072
    $result = 1 === Database::num_rows($res);
3073
3074
    return $result;
3075
}
3076
3077
/**
3078
 * Returns the user's numeric status ID from the users table.
3079
 *
3080
 * @param int $user_id If none provided, will use current user
3081
 *
3082
 * @return int User's status (1 for teacher, 5 for student, etc)
3083
 */
3084
function api_get_user_status($user_id = null)
3085
{
3086
    $user_id = (int) $user_id;
3087
    if (empty($user_id)) {
3088
        $user_id = api_get_user_id();
3089
    }
3090
    $table = Database::get_main_table(TABLE_MAIN_USER);
3091
    $sql = "SELECT status FROM $table WHERE id = $user_id ";
3092
    $result = Database::query($sql);
3093
    $status = null;
3094
    if (Database::num_rows($result)) {
3095
        $row = Database::fetch_array($result);
3096
        $status = $row['status'];
3097
    }
3098
3099
    return $status;
3100
}
3101
3102
/**
3103
 * Checks whether current user is allowed to create courses.
3104
 *
3105
 * @return bool true if the user has course creation rights,
3106
 *              false otherwise
3107
 */
3108
function api_is_allowed_to_create_course()
3109
{
3110
    if (api_is_platform_admin()) {
3111
        return true;
3112
    }
3113
3114
    // Teachers can only create courses
3115
    if (api_is_teacher()) {
3116
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3117
            return true;
3118
        } else {
3119
            return false;
3120
        }
3121
    }
3122
3123
    return Session::read('is_allowedCreateCourse');
3124
}
3125
3126
/**
3127
 * Checks whether the current user is a course administrator.
3128
 *
3129
 * @return bool True if current user is a course administrator
3130
 */
3131
function api_is_course_admin()
3132
{
3133
    if (api_is_platform_admin()) {
3134
        return true;
3135
    }
3136
3137
    $user = api_get_current_user();
3138
    if ($user) {
3139
        if (
3140
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
3141
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3142
        ) {
3143
            return true;
3144
        }
3145
    }
3146
3147
    return false;
3148
    //return Session::read('is_courseAdmin');
3149
}
3150
3151
/**
3152
 * Checks whether the current user is a course coach
3153
 * Based on the presence of user in session.id_coach (session general coach).
3154
 *
3155
 * @return bool True if current user is a course coach
3156
 */
3157
function api_is_session_general_coach()
3158
{
3159
    return Session::read('is_session_general_coach');
3160
}
3161
3162
/**
3163
 * Checks whether the current user is a course tutor
3164
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3165
 *
3166
 * @return bool True if current user is a course tutor
3167
 */
3168
function api_is_course_tutor()
3169
{
3170
    return Session::read('is_courseTutor');
3171
}
3172
3173
/**
3174
 * @param int $user_id
3175
 * @param int $courseId
3176
 * @param int $session_id
3177
 *
3178
 * @return bool
3179
 */
3180
function api_is_course_session_coach($user_id, $courseId, $session_id)
3181
{
3182
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3183
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3184
3185
    $user_id = (int) $user_id;
3186
    $session_id = (int) $session_id;
3187
    $courseId = (int) $courseId;
3188
3189
    $sql = "SELECT DISTINCT session.id
3190
            FROM $session_table
3191
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3192
            ON session.id = session_rc_ru.session_id
3193
            WHERE
3194
                session_rc_ru.user_id = '".$user_id."'  AND
3195
                session_rc_ru.c_id = '$courseId' AND
3196
                session_rc_ru.status = 2 AND
3197
                session_rc_ru.session_id = '$session_id'";
3198
    $result = Database::query($sql);
3199
3200
    return Database::num_rows($result) > 0;
3201
}
3202
3203
/**
3204
 * Checks whether the current user is a course or session coach.
3205
 *
3206
 * @param int $session_id
3207
 * @param int $courseId
3208
 * @param bool  Check whether we are in student view and, if we are, return false
3209
 *
3210
 * @return bool True if current user is a course or session coach
3211
 */
3212
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3213
{
3214
    $userId = api_get_user_id();
3215
3216
    if (!empty($session_id)) {
3217
        $session_id = (int) $session_id;
3218
    } else {
3219
        $session_id = api_get_session_id();
3220
    }
3221
3222
    // The student preview was on
3223
    if ($check_student_view && api_is_student_view_active()) {
3224
        return false;
3225
    }
3226
3227
    if (!empty($courseId)) {
3228
        $courseId = (int) $courseId;
3229
    } else {
3230
        $courseId = api_get_course_int_id();
3231
    }
3232
3233
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3234
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3235
    $sessionIsCoach = [];
3236
3237
    if (!empty($courseId)) {
3238
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3239
                FROM $session_table s
3240
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3241
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3242
                WHERE
3243
                    session_rc_ru.c_id = '$courseId' AND
3244
                    session_rc_ru.status = 2 AND
3245
                    session_rc_ru.session_id = '$session_id'";
3246
        $result = Database::query($sql);
3247
        $sessionIsCoach = Database::store_result($result);
3248
    }
3249
3250
    if (!empty($session_id)) {
3251
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3252
                FROM $session_table
3253
                WHERE session.id_coach = $userId AND id = $session_id
3254
                ORDER BY access_start_date, access_end_date, name";
3255
        $result = Database::query($sql);
3256
        if (!empty($sessionIsCoach)) {
3257
            $sessionIsCoach = array_merge(
3258
                $sessionIsCoach,
3259
                Database::store_result($result)
3260
            );
3261
        } else {
3262
            $sessionIsCoach = Database::store_result($result);
3263
        }
3264
    }
3265
3266
    return count($sessionIsCoach) > 0;
3267
}
3268
3269
/**
3270
 * Checks whether the current user is a session administrator.
3271
 *
3272
 * @return bool True if current user is a course administrator
3273
 */
3274
function api_is_session_admin()
3275
{
3276
    $user = api_get_user_info();
3277
3278
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3279
}
3280
3281
/**
3282
 * Checks whether the current user is a human resources manager.
3283
 *
3284
 * @return bool True if current user is a human resources manager
3285
 */
3286
function api_is_drh()
3287
{
3288
    $user = api_get_user_info();
3289
3290
    return isset($user['status']) && DRH == $user['status'];
3291
}
3292
3293
/**
3294
 * Checks whether the current user is a student.
3295
 *
3296
 * @return bool True if current user is a human resources manager
3297
 */
3298
function api_is_student()
3299
{
3300
    $user = api_get_user_info();
3301
3302
    return isset($user['status']) && STUDENT == $user['status'];
3303
}
3304
3305
/**
3306
 * Checks whether the current user has the status 'teacher'.
3307
 *
3308
 * @return bool True if current user is a human resources manager
3309
 */
3310
function api_is_teacher()
3311
{
3312
    $user = api_get_user_info();
3313
3314
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3315
}
3316
3317
/**
3318
 * Checks whether the current user is a invited user.
3319
 *
3320
 * @return bool
3321
 */
3322
function api_is_invitee()
3323
{
3324
    $user = api_get_user_info();
3325
3326
    return isset($user['status']) && INVITEE == $user['status'];
3327
}
3328
3329
/**
3330
 * This function checks whether a session is assigned into a category.
3331
 *
3332
 * @param int       - session id
3333
 * @param string    - category name
3334
 *
3335
 * @return bool - true if is found, otherwise false
3336
 */
3337
function api_is_session_in_category($session_id, $category_name)
3338
{
3339
    $session_id = (int) $session_id;
3340
    $category_name = Database::escape_string($category_name);
3341
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3342
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3343
3344
    $sql = "SELECT 1
3345
            FROM $tbl_session
3346
            WHERE $session_id IN (
3347
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3348
                WHERE
3349
                  s.session_category_id = sc.id AND
3350
                  sc.name LIKE '%$category_name'
3351
            )";
3352
    $rs = Database::query($sql);
3353
3354
    if (Database::num_rows($rs) > 0) {
3355
        return true;
3356
    } else {
3357
        return false;
3358
    }
3359
}
3360
3361
/**
3362
 * Displays the title of a tool.
3363
 * Normal use: parameter is a string:
3364
 * api_display_tool_title("My Tool").
3365
 *
3366
 * Optionally, there can be a subtitle below
3367
 * the normal title, and / or a supra title above the normal title.
3368
 *
3369
 * e.g. supra title:
3370
 * group
3371
 * GROUP PROPERTIES
3372
 *
3373
 * e.g. subtitle:
3374
 * AGENDA
3375
 * calender & events tool
3376
 *
3377
 * @author Hugues Peeters <[email protected]>
3378
 *
3379
 * @param mixed $title_element - it could either be a string or an array
3380
 *                             containing 'supraTitle', 'mainTitle',
3381
 *                             'subTitle'
3382
 */
3383
function api_display_tool_title($title_element)
3384
{
3385
    if (is_string($title_element)) {
3386
        $tit = $title_element;
3387
        unset($title_element);
3388
        $title_element = [];
3389
        $title_element['mainTitle'] = $tit;
3390
    }
3391
    echo '<h3>';
3392
    if (!empty($title_element['supraTitle'])) {
3393
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3394
    }
3395
    if (!empty($title_element['mainTitle'])) {
3396
        echo $title_element['mainTitle'];
3397
    }
3398
    if (!empty($title_element['subTitle'])) {
3399
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3400
    }
3401
    echo '</h3>';
3402
}
3403
3404
/**
3405
 * Displays options for switching between student view and course manager view.
3406
 *
3407
 * Changes in version 1.2 (Patrick Cool)
3408
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3409
 * is changed explicitly
3410
 *
3411
 * Changes in version 1.1 (Patrick Cool)
3412
 * student view now works correctly in subfolders of the document tool
3413
 * student view works correctly in the new links tool
3414
 *
3415
 * Example code for using this in your tools:
3416
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3417
 * //   display_tool_view_option($isStudentView);
3418
 * //}
3419
 * //and in later sections, use api_is_allowed_to_edit()
3420
 *
3421
 * @author Roan Embrechts
3422
 * @author Patrick Cool
3423
 * @author Julio Montoya, changes added in Chamilo
3424
 *
3425
 * @version 1.2
3426
 *
3427
 * @todo rewrite code so it is easier to understand
3428
 */
3429
function api_display_tool_view_option()
3430
{
3431
    if ('true' != api_get_setting('student_view_enabled')) {
3432
        return '';
3433
    }
3434
3435
    $sourceurl = '';
3436
    $is_framed = false;
3437
    // Exceptions apply for all multi-frames pages
3438
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3439
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3440
        return '';
3441
    }
3442
3443
    // Uncomment to remove student view link from document view page
3444
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3445
        if (empty($_GET['lp_id'])) {
3446
            return '';
3447
        }
3448
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3449
        $sourceurl = str_replace(
3450
            'lp/lp_header.php',
3451
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3452
            $sourceurl
3453
        );
3454
        //showinframes doesn't handle student view anyway...
3455
        //return '';
3456
        $is_framed = true;
3457
    }
3458
3459
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3460
    if (!$is_framed) {
3461
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3462
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3463
        } else {
3464
            $sourceurl = $_SERVER['REQUEST_URI'];
3465
        }
3466
    }
3467
3468
    $output_string = '';
3469
    if (!empty($_SESSION['studentview'])) {
3470
        if ('studentview' == $_SESSION['studentview']) {
3471
            // We have to remove the isStudentView=true from the $sourceurl
3472
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3473
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3474
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3475
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3476
        } elseif ('teacherview' == $_SESSION['studentview']) {
3477
            // Switching to teacherview
3478
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3479
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3480
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3481
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3482
        }
3483
    } else {
3484
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3485
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3486
    }
3487
    $output_string = Security::remove_XSS($output_string);
3488
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3489
3490
    return $html;
3491
}
3492
3493
// TODO: This is for the permission section.
3494
/**
3495
 * Function that removes the need to directly use is_courseAdmin global in
3496
 * tool scripts. It returns true or false depending on the user's rights in
3497
 * this particular course.
3498
 * Optionally checking for tutor and coach roles here allows us to use the
3499
 * student_view feature altogether with these roles as well.
3500
 *
3501
 * @param bool  Whether to check if the user has the tutor role
3502
 * @param bool  Whether to check if the user has the coach role
3503
 * @param bool  Whether to check if the user has the session coach role
3504
 * @param bool  check the student view or not
3505
 *
3506
 * @author Roan Embrechts
3507
 * @author Patrick Cool
3508
 * @author Julio Montoya
3509
 *
3510
 * @version 1.1, February 2004
3511
 *
3512
 * @return bool true: the user has the rights to edit, false: he does not
3513
 */
3514
function api_is_allowed_to_edit(
3515
    $tutor = false,
3516
    $coach = false,
3517
    $session_coach = false,
3518
    $check_student_view = true
3519
) {
3520
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3521
    // Admins can edit anything.
3522
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3523
        //The student preview was on
3524
        if ($check_student_view && api_is_student_view_active()) {
3525
            return false;
3526
        }
3527
3528
        return true;
3529
    }
3530
3531
    $sessionId = api_get_session_id();
3532
3533
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3534
        $efv = new ExtraFieldValue('course');
3535
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3536
            api_get_course_int_id(),
3537
            'session_courses_read_only_mode'
3538
        );
3539
3540
        if (!empty($lockExrafieldField['value'])) {
3541
            return false;
3542
        }
3543
    }
3544
3545
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3546
    $session_visibility = api_get_session_visibility($sessionId);
3547
    $is_courseAdmin = api_is_course_admin();
3548
3549
    if (!$is_courseAdmin && $tutor) {
3550
        // If we also want to check if the user is a tutor...
3551
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3552
    }
3553
3554
    if (!$is_courseAdmin && $coach) {
3555
        // If we also want to check if the user is a coach...';
3556
        // Check if session visibility is read only for coaches.
3557
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3558
            $is_allowed_coach_to_edit = false;
3559
        }
3560
3561
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3562
            // Check if coach is allowed to edit a course.
3563
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3564
        }
3565
    }
3566
3567
    if (!$is_courseAdmin && $session_coach) {
3568
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3569
    }
3570
3571
    // Check if the student_view is enabled, and if so, if it is activated.
3572
    if ('true' === api_get_setting('student_view_enabled')) {
3573
        $studentView = api_is_student_view_active();
3574
        if (!empty($sessionId)) {
3575
            // Check if session visibility is read only for coaches.
3576
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3577
                $is_allowed_coach_to_edit = false;
3578
            }
3579
3580
            $is_allowed = false;
3581
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3582
                // Check if coach is allowed to edit a course.
3583
                $is_allowed = $is_allowed_coach_to_edit;
3584
            }
3585
            if ($check_student_view) {
3586
                $is_allowed = $is_allowed && false === $studentView;
3587
            }
3588
        } else {
3589
            $is_allowed = $is_courseAdmin;
3590
            if ($check_student_view) {
3591
                $is_allowed = $is_courseAdmin && false === $studentView;
3592
            }
3593
        }
3594
3595
        return $is_allowed;
3596
    } else {
3597
        return $is_courseAdmin;
3598
    }
3599
}
3600
3601
/**
3602
 * Returns true if user is a course coach of at least one course in session.
3603
 *
3604
 * @param int $sessionId
3605
 *
3606
 * @return bool
3607
 */
3608
function api_is_coach_of_course_in_session($sessionId)
3609
{
3610
    if (api_is_platform_admin()) {
3611
        return true;
3612
    }
3613
3614
    $userId = api_get_user_id();
3615
    $courseList = UserManager::get_courses_list_by_session(
3616
        $userId,
3617
        $sessionId
3618
    );
3619
3620
    // Session visibility.
3621
    $visibility = api_get_session_visibility(
3622
        $sessionId,
3623
        null,
3624
        false
3625
    );
3626
3627
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3628
        // Course Coach session visibility.
3629
        $blockedCourseCount = 0;
3630
        $closedVisibilityList = [
3631
            COURSE_VISIBILITY_CLOSED,
3632
            COURSE_VISIBILITY_HIDDEN,
3633
        ];
3634
3635
        foreach ($courseList as $course) {
3636
            // Checking session visibility
3637
            $sessionCourseVisibility = api_get_session_visibility(
3638
                $sessionId,
3639
                $course['real_id']
3640
            );
3641
3642
            $courseIsVisible = !in_array(
3643
                $course['visibility'],
3644
                $closedVisibilityList
3645
            );
3646
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3647
                $blockedCourseCount++;
3648
            }
3649
        }
3650
3651
        // If all courses are blocked then no show in the list.
3652
        if ($blockedCourseCount === count($courseList)) {
3653
            $visibility = SESSION_INVISIBLE;
3654
        } else {
3655
            $visibility = SESSION_VISIBLE;
3656
        }
3657
    }
3658
3659
    switch ($visibility) {
3660
        case SESSION_VISIBLE_READ_ONLY:
3661
        case SESSION_VISIBLE:
3662
        case SESSION_AVAILABLE:
3663
            return true;
3664
            break;
3665
        case SESSION_INVISIBLE:
3666
            return false;
3667
    }
3668
3669
    return false;
3670
}
3671
3672
/**
3673
 * Checks if a student can edit contents in a session depending
3674
 * on the session visibility.
3675
 *
3676
 * @param bool $tutor Whether to check if the user has the tutor role
3677
 * @param bool $coach Whether to check if the user has the coach role
3678
 *
3679
 * @return bool true: the user has the rights to edit, false: he does not
3680
 */
3681
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3682
{
3683
    if (api_is_allowed_to_edit($tutor, $coach)) {
3684
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3685
        return true;
3686
    } else {
3687
        $sessionId = api_get_session_id();
3688
3689
        if (0 == $sessionId) {
3690
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3691
            return true;
3692
        } else {
3693
            // I'm in a session and I'm a student
3694
            // Get the session visibility
3695
            $session_visibility = api_get_session_visibility($sessionId);
3696
            // if 5 the session is still available
3697
            switch ($session_visibility) {
3698
                case SESSION_VISIBLE_READ_ONLY: // 1
3699
                    return false;
3700
                case SESSION_VISIBLE:           // 2
3701
                    return true;
3702
                case SESSION_INVISIBLE:         // 3
3703
                    return false;
3704
                case SESSION_AVAILABLE:         //5
3705
                    return true;
3706
            }
3707
        }
3708
    }
3709
3710
    return false;
3711
}
3712
3713
/**
3714
 * Checks whether the user is allowed in a specific tool for a specific action.
3715
 *
3716
 * @param string $tool   the tool we are checking if the user has a certain permission
3717
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3718
 *
3719
 * @return bool
3720
 *
3721
 * @author Patrick Cool <[email protected]>, Ghent University
3722
 * @author Julio Montoya
3723
 *
3724
 * @version 1.0
3725
 */
3726
function api_is_allowed($tool, $action, $task_id = 0)
3727
{
3728
    $_user = api_get_user_info();
3729
    $_course = api_get_course_info();
3730
3731
    if (api_is_course_admin()) {
3732
        return true;
3733
    }
3734
3735
    if (is_array($_course) and count($_course) > 0) {
3736
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3737
3738
        // Getting the permissions of this user.
3739
        if (0 == $task_id) {
3740
            $user_permissions = get_permissions('user', $_user['user_id']);
3741
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3742
        }
3743
3744
        // Getting the permissions of the task.
3745
        if (0 != $task_id) {
3746
            $task_permissions = get_permissions('task', $task_id);
3747
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3748
        }
3749
    }
3750
3751
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3752
    if ('limited' == api_get_setting('permissions')) {
3753
        if ('Visibility' == $action) {
3754
            $action = 'Edit';
3755
        }
3756
        if ('Move' == $action) {
3757
            $action = 'Edit';
3758
        }
3759
    }
3760
3761
    // The session that contains all the permissions already exists for this course
3762
    // so there is no need to requery everything.
3763
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3764
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3765
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3766
            return true;
3767
        } else {
3768
            return false;
3769
        }
3770
    }
3771
3772
    return false;
3773
}
3774
3775
/**
3776
 * Tells whether this user is an anonymous user.
3777
 *
3778
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3779
 * @param bool $db_check Whether to check in the database (true) or simply in
3780
 *                       the session (false) to see if the current user is the anonymous user
3781
 *
3782
 * @return bool true if this user is anonymous, false otherwise
3783
 */
3784
function api_is_anonymous($user_id = null, $db_check = false)
3785
{
3786
    /*if ($db_check) {
3787
        if (!isset($user_id)) {
3788
            $user_id = api_get_user_id();
3789
        }
3790
3791
        $info = api_get_user_info($user_id);
3792
3793
        if (6 == $info['status'] || 0 == $user_id || empty($info)) {
3794
            return true;
3795
        }
3796
    }*/
3797
3798
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3799
}
3800
3801
/**
3802
 * Displays message "You are not allowed here..." and exits the entire script.
3803
 *
3804
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3805
 * @param string $message
3806
 * @param int    $responseCode
3807
 */
3808
function api_not_allowed(
3809
    $print_headers = false,
3810
    $message = null,
3811
    $responseCode = 0
3812
) {
3813
    throw new Exception('You are not allowed');
3814
}
3815
3816
/**
3817
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3818
 *
3819
 * @param $last_post_datetime standard output date in a sql query
3820
 *
3821
 * @return int timestamp
3822
 *
3823
 * @author Toon Van Hoecke <[email protected]>
3824
 *
3825
 * @version October 2003
3826
 * @desc convert sql date to unix timestamp
3827
 */
3828
function convert_sql_date($last_post_datetime)
3829
{
3830
    [$last_post_date, $last_post_time] = explode(' ', $last_post_datetime);
3831
    [$year, $month, $day] = explode('-', $last_post_date);
3832
    [$hour, $min, $sec] = explode(':', $last_post_time);
3833
3834
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3835
}
3836
3837
/**
3838
 * Delete a row in the c_item_property table.
3839
 *
3840
 * @param array  $courseInfo
3841
 * @param string $tool
3842
 * @param int    $itemId
3843
 * @param int    $userId
3844
 * @param int    $groupId    group.iid
3845
 * @param int    $sessionId
3846
 *
3847
 * @return false|null
3848
 */
3849
function api_item_property_delete(
3850
    $courseInfo,
3851
    $tool,
3852
    $itemId,
3853
    $userId,
3854
    $groupId = 0,
3855
    $sessionId = 0
3856
) {
3857
    if (empty($courseInfo)) {
3858
        return false;
3859
    }
3860
3861
    $courseId = (int) $courseInfo['real_id'];
3862
3863
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3864
        return false;
3865
    }
3866
3867
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3868
    $tool = Database::escape_string($tool);
3869
    $itemId = intval($itemId);
3870
    $userId = intval($userId);
3871
    $groupId = intval($groupId);
3872
    $sessionId = intval($sessionId);
3873
3874
    $groupCondition = " AND to_group_id = $groupId ";
3875
    if (empty($groupId)) {
3876
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3877
    }
3878
3879
    $userCondition = " AND to_user_id = $userId ";
3880
    if (empty($userId)) {
3881
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3882
    }
3883
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3884
    $sql = "DELETE FROM $table
3885
            WHERE
3886
                c_id = $courseId AND
3887
                tool  = '$tool' AND
3888
                ref = $itemId
3889
                $sessionCondition
3890
                $userCondition
3891
                $groupCondition
3892
            ";
3893
3894
    Database::query($sql);
3895
}
3896
3897
/**
3898
 * Gets item property by tool.
3899
 *
3900
 * @param string    course code
3901
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3902
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
3903
 * @param int    $session_id
3904
 * @param string $tool
3905
 * @param string $course_code
3906
 *
3907
 * @return array All fields from c_item_property (all rows found) or empty array
3908
 */
3909
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
3910
{
3911
    $course_info = api_get_course_info($course_code);
3912
    $tool = Database::escape_string($tool);
3913
3914
    // Definition of tables.
3915
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3916
    $session_id = (int) $session_id;
3917
    $session_condition = ' AND session_id = '.$session_id;
3918
    if (empty($session_id)) {
3919
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3920
    }
3921
    $course_id = $course_info['real_id'];
3922
3923
    $sql = "SELECT * FROM $item_property_table
3924
            WHERE
3925
                c_id = $course_id AND
3926
                tool = '$tool'
3927
                $session_condition ";
3928
    $rs = Database::query($sql);
3929
    $list = [];
3930
    if (Database::num_rows($rs) > 0) {
3931
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3932
            $list[] = $row;
3933
        }
3934
    }
3935
3936
    return $list;
3937
}
3938
3939
/**
3940
 * Gets item property by tool and user.
3941
 *
3942
 * @param int $userId
3943
 * @param int $tool
3944
 * @param int $courseId
3945
 * @param int $session_id
3946
 *
3947
 * @return array
3948
 */
3949
function api_get_item_property_list_by_tool_by_user(
3950
    $userId,
3951
    $tool,
3952
    $courseId,
3953
    $session_id = 0
3954
) {
3955
    $userId = intval($userId);
3956
    $tool = Database::escape_string($tool);
3957
    $session_id = intval($session_id);
3958
    $courseId = intval($courseId);
3959
3960
    // Definition of tables.
3961
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3962
    $session_condition = ' AND session_id = '.$session_id;
3963
    if (empty($session_id)) {
3964
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3965
    }
3966
    $sql = "SELECT * FROM $item_property_table
3967
            WHERE
3968
                insert_user_id = $userId AND
3969
                c_id = $courseId AND
3970
                tool = '$tool'
3971
                $session_condition ";
3972
3973
    $rs = Database::query($sql);
3974
    $list = [];
3975
    if (Database::num_rows($rs) > 0) {
3976
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3977
            $list[] = $row;
3978
        }
3979
    }
3980
3981
    return $list;
3982
}
3983
3984
/**
3985
 * Gets item property id from tool of a course.
3986
 *
3987
 * @param string $course_code course code
3988
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3989
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
3990
 * @param int    $sessionId   Session ID (optional)
3991
 *
3992
 * @return int
3993
 */
3994
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
3995
{
3996
    $course_info = api_get_course_info($course_code);
3997
    $tool = Database::escape_string($tool);
3998
    $ref = (int) $ref;
3999
4000
    // Definition of tables.
4001
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4002
    $course_id = $course_info['real_id'];
4003
    $sessionId = (int) $sessionId;
4004
    $sessionCondition = " AND session_id = $sessionId ";
4005
    if (empty($sessionId)) {
4006
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4007
    }
4008
    $sql = "SELECT id FROM $tableItemProperty
4009
            WHERE
4010
                c_id = $course_id AND
4011
                tool = '$tool' AND
4012
                ref = $ref
4013
                $sessionCondition";
4014
    $rs = Database::query($sql);
4015
    $item_property_id = '';
4016
    if (Database::num_rows($rs) > 0) {
4017
        $row = Database::fetch_array($rs);
4018
        $item_property_id = $row['id'];
4019
    }
4020
4021
    return $item_property_id;
4022
}
4023
4024
/**
4025
 * Inserts a record in the track_e_item_property table (No update).
4026
 *
4027
 * @param string $tool
4028
 * @param int    $ref
4029
 * @param string $title
4030
 * @param string $content
4031
 * @param int    $progress
4032
 *
4033
 * @return bool|int
4034
 */
4035
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4036
{
4037
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4038
    $course_id = api_get_course_int_id(); //numeric
4039
    $course_code = api_get_course_id(); //alphanumeric
4040
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4041
    if (!empty($item_property_id)) {
4042
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4043
                course_id           = '$course_id',
4044
                item_property_id    = '$item_property_id',
4045
                title               = '".Database::escape_string($title)."',
4046
                content             = '".Database::escape_string($content)."',
4047
                progress            = '".intval($progress)."',
4048
                lastedit_date       = '".api_get_utc_datetime()."',
4049
                lastedit_user_id    = '".api_get_user_id()."',
4050
                session_id          = '".api_get_session_id()."'";
4051
        $result = Database::query($sql);
4052
        $affected_rows = Database::affected_rows($result);
4053
4054
        return $affected_rows;
4055
    }
4056
4057
    return false;
4058
}
4059
4060
/**
4061
 * @param string $tool
4062
 * @param int    $ref
4063
 *
4064
 * @return array|resource
4065
 */
4066
function api_get_track_item_property_history($tool, $ref)
4067
{
4068
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4069
    $course_id = api_get_course_int_id(); //numeric
4070
    $course_code = api_get_course_id(); //alphanumeric
4071
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4072
    $sql = "SELECT * FROM $tbl_stats_item_property
4073
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4074
            ORDER BY lastedit_date DESC";
4075
    $result = Database::query($sql);
4076
    if (false === $result or null === $result) {
4077
        $result = [];
4078
    } else {
4079
        $result = Database::store_result($result, 'ASSOC');
4080
    }
4081
4082
    return $result;
4083
}
4084
4085
/**
4086
 * Gets item property data from tool of a course id.
4087
 *
4088
 * @deprecated
4089
 *
4090
 * @param int    $course_id
4091
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4092
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4093
 * @param int    $session_id
4094
 * @param int    $groupId
4095
 *
4096
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4097
 */
4098
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4099
{
4100
    $courseInfo = api_get_course_info_by_id($course_id);
4101
4102
    if (empty($courseInfo)) {
4103
        return false;
4104
    }
4105
4106
    $tool = Database::escape_string($tool);
4107
    $course_id = $courseInfo['real_id'];
4108
    $ref = (int) $ref;
4109
    $session_id = (int) $session_id;
4110
4111
    $sessionCondition = " session_id = $session_id";
4112
    if (empty($session_id)) {
4113
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4114
    }
4115
4116
    // Definition of tables.
4117
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4118
4119
    $sql = "SELECT * FROM $table
4120
            WHERE
4121
                c_id = $course_id AND
4122
                tool = '$tool' AND
4123
                ref = $ref AND
4124
                $sessionCondition ";
4125
4126
    if (!empty($groupId)) {
4127
        $groupId = (int) $groupId;
4128
        $sql .= " AND to_group_id = $groupId ";
4129
    }
4130
4131
    $rs = Database::query($sql);
4132
    $row = [];
4133
    if (Database::num_rows($rs) > 0) {
4134
        $row = Database::fetch_array($rs, 'ASSOC');
4135
    }
4136
4137
    return $row;
4138
}
4139
4140
/**
4141
 * Displays a combo box so the user can select his/her preferred language.
4142
 *
4143
 * @param string The desired name= value for the select
4144
 * @param bool Whether we use the JQuery Chozen library or not
4145
 * (in some cases, like the indexing language picker, it can alter the presentation)
4146
 *
4147
 * @deprecated
4148
 *
4149
 * @return string
4150
 */
4151
function api_get_languages_combo($name = 'language')
4152
{
4153
    $ret = '';
4154
    $platformLanguage = api_get_setting('platformLanguage');
4155
4156
    // Retrieve a complete list of all the languages.
4157
    $language_list = api_get_languages();
4158
4159
    if (count($language_list) < 2) {
4160
        return $ret;
4161
    }
4162
4163
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4164
    if (isset($_SESSION['user_language_choice'])) {
4165
        $default = $_SESSION['user_language_choice'];
4166
    } else {
4167
        $default = $platformLanguage;
4168
    }
4169
4170
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4171
    foreach ($language_list as $key => $value) {
4172
        if ($key == $default) {
4173
            $selected = ' selected="selected"';
4174
        } else {
4175
            $selected = '';
4176
        }
4177
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4178
    }
4179
    $ret .= '</select>';
4180
4181
    return $ret;
4182
}
4183
4184
/**
4185
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4186
 * The form works with or without javascript.
4187
 *
4188
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4189
 * @param bool $showAsButton
4190
 *
4191
 * @return string|null Display the box directly
4192
 */
4193
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4194
{
4195
    // Retrieve a complete list of all the languages.
4196
    $language_list = api_get_languages();
4197
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4198
        return; //don't show any form
4199
    }
4200
4201
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4202
    if (isset($_SESSION['user_language_choice'])) {
4203
        $user_selected_language = $_SESSION['user_language_choice'];
4204
    }
4205
    if (empty($user_selected_language)) {
4206
        $user_selected_language = api_get_setting('platformLanguage');
4207
    }
4208
4209
    $currentLanguageId = api_get_language_id($user_selected_language);
4210
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4211
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4212
    $url = api_get_self();
4213
    if ($showAsButton) {
4214
        $html = '<div class="btn-group">
4215
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4216
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4217
                '.$currentLanguageInfo['original_name'].'
4218
                <span class="caret">
4219
                </span>
4220
              </button>';
4221
    } else {
4222
        $html = '
4223
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4224
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4225
                '.$currentLanguageInfo['original_name'].'
4226
                <span class="caret"></span>
4227
            </a>
4228
            ';
4229
    }
4230
4231
    $html .= '<ul class="dropdown-menu" role="menu">';
4232
    foreach ($language_list['all'] as $key => $data) {
4233
        $urlLink = $url.'?language='.$data['english_name'];
4234
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4235
    }
4236
    $html .= '</ul>';
4237
4238
    if ($showAsButton) {
4239
        $html .= '</div>';
4240
    }
4241
4242
    return $html;
4243
}
4244
4245
/**
4246
 * @param string $languageIsoCode
4247
 *
4248
 * @return string
4249
 */
4250
function languageToCountryIsoCode($languageIsoCode)
4251
{
4252
    $allow = api_get_configuration_value('language_flags_by_country');
4253
4254
    // @todo save in DB
4255
    switch ($languageIsoCode) {
4256
        case 'ar':
4257
            $country = 'ae';
4258
            break;
4259
        case 'bs':
4260
            $country = 'ba';
4261
            break;
4262
        case 'ca':
4263
            $country = 'es';
4264
            if ($allow) {
4265
                $country = 'catalan';
4266
            }
4267
            break;
4268
        case 'cs':
4269
            $country = 'cz';
4270
            break;
4271
        case 'da':
4272
            $country = 'dk';
4273
            break;
4274
        case 'el':
4275
            $country = 'ae';
4276
            break;
4277
        case 'en':
4278
            $country = 'gb';
4279
            break;
4280
        case 'eu': // Euskera
4281
            $country = 'es';
4282
            if ($allow) {
4283
                $country = 'basque';
4284
            }
4285
            break;
4286
        case 'gl': // galego
4287
            $country = 'es';
4288
            if ($allow) {
4289
                $country = 'galician';
4290
            }
4291
            break;
4292
        case 'he':
4293
            $country = 'il';
4294
            break;
4295
        case 'ja':
4296
            $country = 'jp';
4297
            break;
4298
        case 'ka':
4299
            $country = 'ge';
4300
            break;
4301
        case 'ko':
4302
            $country = 'kr';
4303
            break;
4304
        case 'ms':
4305
            $country = 'my';
4306
            break;
4307
        case 'pt-BR':
4308
            $country = 'br';
4309
            break;
4310
        case 'qu':
4311
            $country = 'pe';
4312
            break;
4313
        case 'sl':
4314
            $country = 'si';
4315
            break;
4316
        case 'sv':
4317
            $country = 'se';
4318
            break;
4319
        case 'uk': // Ukraine
4320
            $country = 'ua';
4321
            break;
4322
        case 'zh-TW':
4323
        case 'zh':
4324
            $country = 'cn';
4325
            break;
4326
        default:
4327
            $country = $languageIsoCode;
4328
            break;
4329
    }
4330
    $country = strtolower($country);
4331
4332
    return $country;
4333
}
4334
4335
/**
4336
 * Returns a list of all the languages that are made available by the admin.
4337
 *
4338
 * @return array An array with all languages. Structure of the array is
4339
 *               array['name'] = An array with the name of every language
4340
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4341
 */
4342
function api_get_languages()
4343
{
4344
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4345
    $sql = "SELECT * FROM $table WHERE available='1'
4346
            ORDER BY original_name ASC";
4347
    $result = Database::query($sql);
4348
    $languages = [];
4349
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4350
        $languages[$row['isocode']] = $row['original_name'];
4351
    }
4352
4353
    return $languages;
4354
}
4355
4356
/**
4357
 * Returns a list of all the languages that are made available by the admin.
4358
 *
4359
 * @return array
4360
 */
4361
function api_get_languages_to_array()
4362
{
4363
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4364
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4365
    $result = Database::query($sql);
4366
    $languages = [];
4367
    while ($row = Database::fetch_array($result)) {
4368
        $languages[$row['english_name']] = $row['original_name'];
4369
    }
4370
4371
    return $languages;
4372
}
4373
4374
/**
4375
 * Returns the id (the database id) of a language.
4376
 *
4377
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4378
 *
4379
 * @return int id of the language
4380
 */
4381
function api_get_language_id($language)
4382
{
4383
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4384
    if (empty($language)) {
4385
        return null;
4386
    }
4387
    $language = Database::escape_string($language);
4388
    $sql = "SELECT id FROM $tbl_language
4389
            WHERE english_name = '$language' LIMIT 1";
4390
    $result = Database::query($sql);
4391
    $row = Database::fetch_array($result);
4392
4393
    return $row['id'];
4394
}
4395
4396
/**
4397
 * Get the language information by its id.
4398
 *
4399
 * @param int $languageId
4400
 *
4401
 * @throws Exception
4402
 *
4403
 * @return array
4404
 */
4405
function api_get_language_info($languageId)
4406
{
4407
    if (empty($languageId)) {
4408
        return [];
4409
    }
4410
4411
    $language = Database::getManager()->find(Language::class, $languageId);
4412
4413
    if (!$language) {
4414
        return [];
4415
    }
4416
4417
    return [
4418
        'id' => $language->getId(),
4419
        'original_name' => $language->getOriginalName(),
4420
        'english_name' => $language->getEnglishName(),
4421
        'isocode' => $language->getIsocode(),
4422
        'available' => $language->getAvailable(),
4423
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4424
    ];
4425
}
4426
4427
/**
4428
 * @param string $code
4429
 *
4430
 * @return Language
4431
 */
4432
function api_get_language_from_iso($code)
4433
{
4434
    $em = Database::getManager();
4435
4436
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
4437
}
4438
4439
/**
4440
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4441
 * The returned name depends on the platform, course or user -wide settings.
4442
 *
4443
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4444
 */
4445
function api_get_visual_theme()
4446
{
4447
    static $visual_theme;
4448
    if (!isset($visual_theme)) {
4449
        // Get style directly from DB
4450
        /*$styleFromDatabase = api_get_settings_params_simple(
4451
            [
4452
                'variable = ? AND access_url = ?' => [
4453
                    'stylesheets',
4454
                    api_get_current_access_url_id(),
4455
                ],
4456
            ]
4457
        );
4458
4459
        if ($styleFromDatabase) {
4460
            $platform_theme = $styleFromDatabase['selected_value'];
4461
        } else {
4462
            $platform_theme = api_get_setting('stylesheets');
4463
        }*/
4464
        $platform_theme = api_get_setting('stylesheets');
4465
4466
        // Platform's theme.
4467
        $visual_theme = $platform_theme;
4468
        if ('true' == api_get_setting('user_selected_theme')) {
4469
            $user_info = api_get_user_info();
4470
            if (isset($user_info['theme'])) {
4471
                $user_theme = $user_info['theme'];
4472
4473
                if (!empty($user_theme)) {
4474
                    $visual_theme = $user_theme;
4475
                    // User's theme.
4476
                }
4477
            }
4478
        }
4479
4480
        $course_id = api_get_course_id();
4481
        if (!empty($course_id)) {
4482
            if ('true' == api_get_setting('allow_course_theme')) {
4483
                $course_theme = api_get_course_setting('course_theme', $course_id);
4484
4485
                if (!empty($course_theme) && -1 != $course_theme) {
4486
                    if (!empty($course_theme)) {
4487
                        // Course's theme.
4488
                        $visual_theme = $course_theme;
4489
                    }
4490
                }
4491
4492
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4493
                if (1 == $allow_lp_theme) {
4494
                    /*global $lp_theme_css, $lp_theme_config;
4495
                    // These variables come from the file lp_controller.php.
4496
                    if (!$lp_theme_config) {
4497
                        if (!empty($lp_theme_css)) {
4498
                            // LP's theme.
4499
                            $visual_theme = $lp_theme_css;
4500
                        }
4501
                    }*/
4502
                }
4503
            }
4504
        }
4505
4506
        if (empty($visual_theme)) {
4507
            $visual_theme = 'chamilo';
4508
        }
4509
4510
        /*global $lp_theme_log;
4511
        if ($lp_theme_log) {
4512
            $visual_theme = $platform_theme;
4513
        }*/
4514
    }
4515
4516
    return $visual_theme;
4517
}
4518
4519
/**
4520
 * Returns a list of CSS themes currently available in the CSS folder
4521
 * The folder must have a default.css file.
4522
 *
4523
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4524
 *
4525
 * @return array list of themes directories from the css folder
4526
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4527
 */
4528
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4529
{
4530
    // This configuration value is set by the vchamilo plugin
4531
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4532
4533
    $readCssFolder = function ($dir) use ($virtualTheme) {
4534
        $finder = new Finder();
4535
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4536
        $list = [];
4537
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4538
        foreach ($themes as $theme) {
4539
            $folder = $theme->getFilename();
4540
            // A theme folder is consider if there's a default.css file
4541
            if (!file_exists($theme->getPathname().'/default.css')) {
4542
                continue;
4543
            }
4544
            $name = ucwords(str_replace('_', ' ', $folder));
4545
            if ($folder == $virtualTheme) {
4546
                continue;
4547
            }
4548
            $list[$folder] = $name;
4549
        }
4550
4551
        return $list;
4552
    };
4553
4554
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4555
    $list = $readCssFolder($dir);
4556
4557
    if (!empty($virtualTheme)) {
4558
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4559
        if ($getOnlyThemeFromVirtualInstance) {
4560
            return $newList;
4561
        }
4562
        $list = $list + $newList;
4563
        asort($list);
4564
    }
4565
4566
    return $list;
4567
}
4568
4569
/**
4570
 * Find the largest sort value in a given user_course_category
4571
 * This function is used when we are moving a course to a different category
4572
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4573
 *
4574
 * @param int $courseCategoryId the id of the user_course_category
4575
 * @param int $userId
4576
 *
4577
 * @return int the value of the highest sort of the user_course_category
4578
 */
4579
function api_max_sort_value($courseCategoryId, $userId)
4580
{
4581
    $user = api_get_user_entity($userId);
4582
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
4583
4584
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
4585
}
4586
4587
/**
4588
 * Transforms a number of seconds in hh:mm:ss format.
4589
 *
4590
 * @author Julian Prud'homme
4591
 *
4592
 * @param int    $seconds      number of seconds
4593
 * @param string $space
4594
 * @param bool   $showSeconds
4595
 * @param bool   $roundMinutes
4596
 *
4597
 * @return string the formatted time
4598
 */
4599
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4600
{
4601
    // $seconds = -1 means that we have wrong data in the db.
4602
    if (-1 == $seconds) {
4603
        return
4604
            get_lang('Unknown').
4605
            Display::return_icon(
4606
                'info2.gif',
4607
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4608
                ['align' => 'absmiddle', 'hspace' => '3px']
4609
            );
4610
    }
4611
4612
    // How many hours ?
4613
    $hours = floor($seconds / 3600);
4614
4615
    // How many minutes ?
4616
    $min = floor(($seconds - ($hours * 3600)) / 60);
4617
4618
    if ($roundMinutes) {
4619
        if ($min >= 45) {
4620
            $min = 45;
4621
        }
4622
4623
        if ($min >= 30 && $min <= 44) {
4624
            $min = 30;
4625
        }
4626
4627
        if ($min >= 15 && $min <= 29) {
4628
            $min = 15;
4629
        }
4630
4631
        if ($min >= 0 && $min <= 14) {
4632
            $min = 0;
4633
        }
4634
    }
4635
4636
    // How many seconds
4637
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4638
4639
    if ($hours < 10) {
4640
        $hours = "0$hours";
4641
    }
4642
4643
    if ($sec < 10) {
4644
        $sec = "0$sec";
4645
    }
4646
4647
    if ($min < 10) {
4648
        $min = "0$min";
4649
    }
4650
4651
    $seconds = '';
4652
    if ($showSeconds) {
4653
        $seconds = $space.$sec;
4654
    }
4655
4656
    return $hours.$space.$min.$seconds;
4657
}
4658
4659
/* FILE SYSTEM RELATED FUNCTIONS */
4660
4661
/**
4662
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4663
 * The return value is based on the platform administrator's setting
4664
 * "Administration > Configuration settings > Security > Permissions for new directories".
4665
 *
4666
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4667
 */
4668
function api_get_permissions_for_new_directories()
4669
{
4670
    static $permissions;
4671
    if (!isset($permissions)) {
4672
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4673
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4674
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4675
    }
4676
4677
    return $permissions;
4678
}
4679
4680
/**
4681
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4682
 * The return value is based on the platform administrator's setting
4683
 * "Administration > Configuration settings > Security > Permissions for new files".
4684
 *
4685
 * @return int returns the permissions in the format
4686
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4687
 */
4688
function api_get_permissions_for_new_files()
4689
{
4690
    static $permissions;
4691
    if (!isset($permissions)) {
4692
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4693
        // The default value 0666 is according to that in the platform
4694
        // administration panel after fresh system installation.
4695
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4696
    }
4697
4698
    return $permissions;
4699
}
4700
4701
/**
4702
 * Deletes a file, or a folder and its contents.
4703
 *
4704
 * @author      Aidan Lister <[email protected]>
4705
 *
4706
 * @version     1.0.3
4707
 *
4708
 * @param string $dirname Directory to delete
4709
 * @param       bool     Deletes only the content or not
4710
 * @param bool $strict if one folder/file fails stop the loop
4711
 *
4712
 * @return bool Returns TRUE on success, FALSE on failure
4713
 *
4714
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4715
 *
4716
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4717
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4718
 */
4719
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4720
{
4721
    $res = true;
4722
    // A sanity check.
4723
    if (!file_exists($dirname)) {
4724
        return false;
4725
    }
4726
    $php_errormsg = '';
4727
    // Simple delete for a file.
4728
    if (is_file($dirname) || is_link($dirname)) {
4729
        $res = unlink($dirname);
4730
        if (false === $res) {
4731
            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);
4732
        }
4733
4734
        return $res;
4735
    }
4736
4737
    // Loop through the folder.
4738
    $dir = dir($dirname);
4739
    // A sanity check.
4740
    $is_object_dir = is_object($dir);
4741
    if ($is_object_dir) {
4742
        while (false !== $entry = $dir->read()) {
4743
            // Skip pointers.
4744
            if ('.' == $entry || '..' == $entry) {
4745
                continue;
4746
            }
4747
4748
            // Recurse.
4749
            if ($strict) {
4750
                $result = rmdirr("$dirname/$entry");
4751
                if (false == $result) {
4752
                    $res = false;
4753
                    break;
4754
                }
4755
            } else {
4756
                rmdirr("$dirname/$entry");
4757
            }
4758
        }
4759
    }
4760
4761
    // Clean up.
4762
    if ($is_object_dir) {
4763
        $dir->close();
4764
    }
4765
4766
    if (false == $delete_only_content_in_folder) {
4767
        $res = rmdir($dirname);
4768
        if (false === $res) {
4769
            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);
4770
        }
4771
    }
4772
4773
    return $res;
4774
}
4775
4776
// TODO: This function is to be simplified. File access modes to be implemented.
4777
/**
4778
 * function adapted from a php.net comment
4779
 * copy recursively a folder.
4780
 *
4781
 * @param the source folder
4782
 * @param the dest folder
4783
 * @param an array of excluded file_name (without extension)
4784
 * @param copied_files the returned array of copied files
4785
 * @param string $source
4786
 * @param string $dest
4787
 */
4788
function copyr($source, $dest, $exclude = [], $copied_files = [])
4789
{
4790
    if (empty($dest)) {
4791
        return false;
4792
    }
4793
    // Simple copy for a file
4794
    if (is_file($source)) {
4795
        $path_info = pathinfo($source);
4796
        if (!in_array($path_info['filename'], $exclude)) {
4797
            copy($source, $dest);
4798
        }
4799
4800
        return true;
4801
    } elseif (!is_dir($source)) {
4802
        //then source is not a dir nor a file, return
4803
        return false;
4804
    }
4805
4806
    // Make destination directory.
4807
    if (!is_dir($dest)) {
4808
        mkdir($dest, api_get_permissions_for_new_directories());
4809
    }
4810
4811
    // Loop through the folder.
4812
    $dir = dir($source);
4813
    while (false !== $entry = $dir->read()) {
4814
        // Skip pointers
4815
        if ('.' == $entry || '..' == $entry) {
4816
            continue;
4817
        }
4818
4819
        // Deep copy directories.
4820
        if ($dest !== "$source/$entry") {
4821
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4822
        }
4823
    }
4824
    // Clean up.
4825
    $dir->close();
4826
4827
    return true;
4828
}
4829
4830
/**
4831
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4832
 * Documentation header to be added here.
4833
 *
4834
 * @param string $pathname
4835
 * @param string $base_path_document
4836
 * @param int    $session_id
4837
 *
4838
 * @return mixed True if directory already exists, false if a file already exists at
4839
 *               the destination and null if everything goes according to plan
4840
 */
4841
function copy_folder_course_session(
4842
    $pathname,
4843
    $base_path_document,
4844
    $session_id,
4845
    $course_info,
4846
    $document,
4847
    $source_course_id
4848
) {
4849
    $table = Database::get_course_table(TABLE_DOCUMENT);
4850
    $session_id = intval($session_id);
4851
    $source_course_id = intval($source_course_id);
4852
4853
    // Check whether directory already exists.
4854
    if (is_dir($pathname) || empty($pathname)) {
4855
        return true;
4856
    }
4857
4858
    // Ensure that a file with the same name does not already exist.
4859
    if (is_file($pathname)) {
4860
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4861
4862
        return false;
4863
    }
4864
4865
    $course_id = $course_info['real_id'];
4866
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4867
    $new_pathname = $base_path_document;
4868
    $path = '';
4869
4870
    foreach ($folders as $folder) {
4871
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4872
        $path .= DIRECTORY_SEPARATOR.$folder;
4873
4874
        if (!file_exists($new_pathname)) {
4875
            $path = Database::escape_string($path);
4876
4877
            $sql = "SELECT * FROM $table
4878
                    WHERE
4879
                        c_id = $source_course_id AND
4880
                        path = '$path' AND
4881
                        filetype = 'folder' AND
4882
                        session_id = '$session_id'";
4883
            $rs1 = Database::query($sql);
4884
            $num_rows = Database::num_rows($rs1);
4885
4886
            if (0 == $num_rows) {
4887
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4888
4889
                // Insert new folder with destination session_id.
4890
                $params = [
4891
                    'c_id' => $course_id,
4892
                    'path' => $path,
4893
                    'comment' => $document->comment,
4894
                    'title' => basename($new_pathname),
4895
                    'filetype' => 'folder',
4896
                    'size' => '0',
4897
                    'session_id' => $session_id,
4898
                ];
4899
                $document_id = Database::insert($table, $params);
4900
                if ($document_id) {
4901
                    /*api_item_property_update(
4902
                        $course_info,
4903
                        TOOL_DOCUMENT,
4904
                        $document_id,
4905
                        'FolderCreated',
4906
                        api_get_user_id(),
4907
                        0,
4908
                        0,
4909
                        null,
4910
                        null,
4911
                        $session_id
4912
                    );*/
4913
                }
4914
            }
4915
        }
4916
    } // en foreach
4917
}
4918
4919
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4920
/**
4921
 * @param string $path
4922
 */
4923
function api_chmod_R($path, $filemode)
4924
{
4925
    if (!is_dir($path)) {
4926
        return chmod($path, $filemode);
4927
    }
4928
4929
    $handler = opendir($path);
4930
    while ($file = readdir($handler)) {
4931
        if ('.' != $file && '..' != $file) {
4932
            $fullpath = "$path/$file";
4933
            if (!is_dir($fullpath)) {
4934
                if (!chmod($fullpath, $filemode)) {
4935
                    return false;
4936
                }
4937
            } else {
4938
                if (!api_chmod_R($fullpath, $filemode)) {
4939
                    return false;
4940
                }
4941
            }
4942
        }
4943
    }
4944
4945
    closedir($handler);
4946
4947
    return chmod($path, $filemode);
4948
}
4949
4950
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4951
/**
4952
 * Parse info file format. (e.g: file.info).
4953
 *
4954
 * Files should use an ini-like format to specify values.
4955
 * White-space generally doesn't matter, except inside values.
4956
 * e.g.
4957
 *
4958
 * @verbatim
4959
 *   key = value
4960
 *   key = "value"
4961
 *   key = 'value'
4962
 *   key = "multi-line
4963
 *
4964
 *   value"
4965
 *   key = 'multi-line
4966
 *
4967
 *   value'
4968
 *   key
4969
 *   =
4970
 *   'value'
4971
 * @endverbatim
4972
 *
4973
 * Arrays are created using a GET-like syntax:
4974
 *
4975
 * @verbatim
4976
 *   key[] = "numeric array"
4977
 *   key[index] = "associative array"
4978
 *   key[index][] = "nested numeric array"
4979
 *   key[index][index] = "nested associative array"
4980
 * @endverbatim
4981
 *
4982
 * PHP constants are substituted in, but only when used as the entire value:
4983
 *
4984
 * Comments should start with a semi-colon at the beginning of a line.
4985
 *
4986
 * This function is NOT for placing arbitrary module-specific settings. Use
4987
 * variable_get() and variable_set() for that.
4988
 *
4989
 * Information stored in the module.info file:
4990
 * - name: The real name of the module for display purposes.
4991
 * - description: A brief description of the module.
4992
 * - dependencies: An array of shortnames of other modules this module depends on.
4993
 * - package: The name of the package of modules this module belongs to.
4994
 *
4995
 * Example of .info file:
4996
 * <code>
4997
 * @verbatim
4998
 *   name = Forum
4999
 *   description = Enables threaded discussions about general topics.
5000
 *   dependencies[] = taxonomy
5001
 *   dependencies[] = comment
5002
 *   package = Core - optional
5003
 *   version = VERSION
5004
 * @endverbatim
5005
 * </code>
5006
 *
5007
 * @param string $filename
5008
 *                         The file we are parsing. Accepts file with relative or absolute path.
5009
 *
5010
 * @return
5011
 *   The info array
5012
 */
5013
function api_parse_info_file($filename)
5014
{
5015
    $info = [];
5016
5017
    if (!file_exists($filename)) {
5018
        return $info;
5019
    }
5020
5021
    $data = file_get_contents($filename);
5022
    if (preg_match_all('
5023
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5024
        ((?:
5025
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5026
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5027
        )+?)
5028
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5029
        (?:
5030
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5031
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5032
          ([^\r\n]*?)                   # Non-quoted string
5033
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5034
        @msx', $data, $matches, PREG_SET_ORDER)) {
5035
        $key = $value1 = $value2 = $value3 = '';
5036
        foreach ($matches as $match) {
5037
            // Fetch the key and value string.
5038
            $i = 0;
5039
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5040
                $$var = isset($match[++$i]) ? $match[$i] : '';
5041
            }
5042
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5043
5044
            // Parse array syntax.
5045
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5046
            $last = array_pop($keys);
5047
            $parent = &$info;
5048
5049
            // Create nested arrays.
5050
            foreach ($keys as $key) {
5051
                if ('' == $key) {
5052
                    $key = count($parent);
5053
                }
5054
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5055
                    $parent[$key] = [];
5056
                }
5057
                $parent = &$parent[$key];
5058
            }
5059
5060
            // Handle PHP constants.
5061
            if (defined($value)) {
5062
                $value = constant($value);
5063
            }
5064
5065
            // Insert actual value.
5066
            if ('' == $last) {
5067
                $last = count($parent);
5068
            }
5069
            $parent[$last] = $value;
5070
        }
5071
    }
5072
5073
    return $info;
5074
}
5075
5076
/**
5077
 * Gets Chamilo version from the configuration files.
5078
 *
5079
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5080
 */
5081
function api_get_version()
5082
{
5083
    return (string) api_get_configuration_value('system_version');
5084
}
5085
5086
/**
5087
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5088
 *
5089
 * @return string
5090
 */
5091
function api_get_software_name()
5092
{
5093
    $name = api_get_configuration_value('software_name');
5094
    if (!empty($name)) {
5095
        return $name;
5096
    } else {
5097
        return 'Chamilo';
5098
    }
5099
}
5100
5101
function api_get_status_list()
5102
{
5103
    $list = [];
5104
    // Table of status
5105
    $list[COURSEMANAGER] = 'teacher'; // 1
5106
    $list[SESSIONADMIN] = 'session_admin'; // 3
5107
    $list[DRH] = 'drh'; // 4
5108
    $list[STUDENT] = 'user'; // 5
5109
    $list[ANONYMOUS] = 'anonymous'; // 6
5110
    $list[INVITEE] = 'invited'; // 20
5111
5112
    return $list;
5113
}
5114
5115
/**
5116
 * Checks whether status given in parameter exists in the platform.
5117
 *
5118
 * @param mixed the status (can be either int either string)
5119
 *
5120
 * @return bool if the status exists, else returns false
5121
 */
5122
function api_status_exists($status_asked)
5123
{
5124
    $list = api_get_status_list();
5125
5126
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5127
}
5128
5129
/**
5130
 * Checks whether status given in parameter exists in the platform. The function
5131
 * returns the status ID or false if it does not exist, but given the fact there
5132
 * is no "0" status, the return value can be checked against
5133
 * if(api_status_key()) to know if it exists.
5134
 *
5135
 * @param   mixed   The status (can be either int or string)
5136
 *
5137
 * @return mixed Status ID if exists, false otherwise
5138
 */
5139
function api_status_key($status)
5140
{
5141
    $list = api_get_status_list();
5142
5143
    return isset($list[$status]) ? $status : array_search($status, $list);
5144
}
5145
5146
/**
5147
 * Gets the status langvars list.
5148
 *
5149
 * @return string[] the list of status with their translations
5150
 */
5151
function api_get_status_langvars()
5152
{
5153
    return [
5154
        COURSEMANAGER => get_lang('Teacher'),
5155
        SESSIONADMIN => get_lang('SessionsAdmin'),
5156
        DRH => get_lang('Human Resources Manager'),
5157
        STUDENT => get_lang('Learner'),
5158
        ANONYMOUS => get_lang('Anonymous'),
5159
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5160
        INVITEE => get_lang('Invited'),
5161
    ];
5162
}
5163
5164
/**
5165
 * The function that retrieves all the possible settings for a certain config setting.
5166
 *
5167
 * @author Patrick Cool <[email protected]>, Ghent University
5168
 */
5169
function api_get_settings_options($var)
5170
{
5171
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5172
    $var = Database::escape_string($var);
5173
    $sql = "SELECT * FROM $table_settings_options
5174
            WHERE variable = '$var'
5175
            ORDER BY id";
5176
    $result = Database::query($sql);
5177
    $settings_options_array = [];
5178
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5179
        $settings_options_array[] = $row;
5180
    }
5181
5182
    return $settings_options_array;
5183
}
5184
5185
/**
5186
 * @param array $params
5187
 */
5188
function api_set_setting_option($params)
5189
{
5190
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5191
    if (empty($params['id'])) {
5192
        Database::insert($table, $params);
5193
    } else {
5194
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5195
    }
5196
}
5197
5198
/**
5199
 * @param array $params
5200
 */
5201
function api_set_setting_simple($params)
5202
{
5203
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5204
    $url_id = api_get_current_access_url_id();
5205
5206
    if (empty($params['id'])) {
5207
        $params['access_url'] = $url_id;
5208
        Database::insert($table, $params);
5209
    } else {
5210
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5211
    }
5212
}
5213
5214
/**
5215
 * @param int $id
5216
 */
5217
function api_delete_setting_option($id)
5218
{
5219
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5220
    if (!empty($id)) {
5221
        Database::delete($table, ['id = ? ' => $id]);
5222
    }
5223
}
5224
5225
/**
5226
 * Sets a platform configuration setting to a given value.
5227
 *
5228
 * @param string    The variable we want to update
5229
 * @param string    The value we want to record
5230
 * @param string    The sub-variable if any (in most cases, this will remain null)
5231
 * @param string    The category if any (in most cases, this will remain null)
5232
 * @param int       The access_url for which this parameter is valid
5233
 * @param string $cat
5234
 *
5235
 * @return bool|null
5236
 */
5237
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5238
{
5239
    if (empty($var)) {
5240
        return false;
5241
    }
5242
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5243
    $var = Database::escape_string($var);
5244
    $value = Database::escape_string($value);
5245
    $access_url = (int) $access_url;
5246
    if (empty($access_url)) {
5247
        $access_url = 1;
5248
    }
5249
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5250
    if (!empty($subvar)) {
5251
        $subvar = Database::escape_string($subvar);
5252
        $select .= " AND subkey = '$subvar'";
5253
    }
5254
    if (!empty($cat)) {
5255
        $cat = Database::escape_string($cat);
5256
        $select .= " AND category = '$cat'";
5257
    }
5258
    if ($access_url > 1) {
5259
        $select .= " AND access_url = $access_url";
5260
    } else {
5261
        $select .= " AND access_url = 1 ";
5262
    }
5263
5264
    $res = Database::query($select);
5265
    if (Database::num_rows($res) > 0) {
5266
        // Found item for this access_url.
5267
        $row = Database::fetch_array($res);
5268
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5269
                WHERE id = ".$row['id'];
5270
        Database::query($sql);
5271
    } else {
5272
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5273
        $select = "SELECT * FROM $t_settings
5274
                   WHERE variable = '$var' AND access_url = 1 ";
5275
        // Just in case
5276
        if (1 == $access_url) {
5277
            if (!empty($subvar)) {
5278
                $select .= " AND subkey = '$subvar'";
5279
            }
5280
            if (!empty($cat)) {
5281
                $select .= " AND category = '$cat'";
5282
            }
5283
            $res = Database::query($select);
5284
            if (Database::num_rows($res) > 0) {
5285
                // We have a setting for access_url 1, but none for the current one, so create one.
5286
                $row = Database::fetch_array($res);
5287
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5288
                        VALUES
5289
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5290
                    "'".$row['type']."','".$row['category']."',".
5291
                    "'$value','".$row['title']."',".
5292
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5293
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5294
                Database::query($insert);
5295
            } else {
5296
                // Such a setting does not exist.
5297
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5298
            }
5299
        } else {
5300
            // Other access url.
5301
            if (!empty($subvar)) {
5302
                $select .= " AND subkey = '$subvar'";
5303
            }
5304
            if (!empty($cat)) {
5305
                $select .= " AND category = '$cat'";
5306
            }
5307
            $res = Database::query($select);
5308
5309
            if (Database::num_rows($res) > 0) {
5310
                // We have a setting for access_url 1, but none for the current one, so create one.
5311
                $row = Database::fetch_array($res);
5312
                if (1 == $row['access_url_changeable']) {
5313
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5314
                            ('".$row['variable']."',".
5315
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5316
                        "'".$row['type']."','".$row['category']."',".
5317
                        "'$value','".$row['title']."',".
5318
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5319
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5320
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5321
                    Database::query($insert);
5322
                }
5323
            } else { // Such a setting does not exist.
5324
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5325
            }
5326
        }
5327
    }
5328
}
5329
5330
/**
5331
 * Sets a whole category of settings to one specific value.
5332
 *
5333
 * @param string    Category
5334
 * @param string    Value
5335
 * @param int       Access URL. Optional. Defaults to 1
5336
 * @param array     Optional array of filters on field type
5337
 * @param string $category
5338
 * @param string $value
5339
 *
5340
 * @return bool
5341
 */
5342
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5343
{
5344
    if (empty($category)) {
5345
        return false;
5346
    }
5347
    $category = Database::escape_string($category);
5348
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5349
    $access_url = (int) $access_url;
5350
    if (empty($access_url)) {
5351
        $access_url = 1;
5352
    }
5353
    if (isset($value)) {
5354
        $value = Database::escape_string($value);
5355
        $sql = "UPDATE $t_s SET selected_value = '$value'
5356
                WHERE category = '$category' AND access_url = $access_url";
5357
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5358
            $sql .= " AND ( ";
5359
            $i = 0;
5360
            foreach ($fieldtype as $type) {
5361
                if ($i > 0) {
5362
                    $sql .= ' OR ';
5363
                }
5364
                $type = Database::escape_string($type);
5365
                $sql .= " type='".$type."' ";
5366
                $i++;
5367
            }
5368
            $sql .= ")";
5369
        }
5370
        $res = Database::query($sql);
5371
5372
        return false !== $res;
5373
    } else {
5374
        $sql = "UPDATE $t_s SET selected_value = NULL
5375
                WHERE category = '$category' AND access_url = $access_url";
5376
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5377
            $sql .= " AND ( ";
5378
            $i = 0;
5379
            foreach ($fieldtype as $type) {
5380
                if ($i > 0) {
5381
                    $sql .= ' OR ';
5382
                }
5383
                $type = Database::escape_string($type);
5384
                $sql .= " type='".$type."' ";
5385
                $i++;
5386
            }
5387
            $sql .= ")";
5388
        }
5389
        $res = Database::query($sql);
5390
5391
        return false !== $res;
5392
    }
5393
}
5394
5395
/**
5396
 * Gets all available access urls in an array (as in the database).
5397
 *
5398
 * @return array An array of database records
5399
 */
5400
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5401
{
5402
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5403
    $from = (int) $from;
5404
    $to = (int) $to;
5405
    $order = Database::escape_string($order, null, false);
5406
    $direction = Database::escape_string($direction, null, false);
5407
    $sql = "SELECT id, url, description, active, created_by, tms
5408
            FROM $table
5409
            ORDER BY $order $direction
5410
            LIMIT $to OFFSET $from";
5411
    $res = Database::query($sql);
5412
5413
    return Database::store_result($res);
5414
}
5415
5416
/**
5417
 * Gets the access url info in an array.
5418
 *
5419
 * @param int  $id            Id of the access url
5420
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5421
 *
5422
 * @return array All the info (url, description, active, created_by, tms)
5423
 *               from the access_url table
5424
 *
5425
 * @author Julio Montoya
5426
 */
5427
function api_get_access_url($id, $returnDefault = true)
5428
{
5429
    static $staticResult;
5430
    $id = (int) $id;
5431
5432
    if (isset($staticResult[$id])) {
5433
        $result = $staticResult[$id];
5434
    } else {
5435
        // Calling the Database:: library dont work this is handmade.
5436
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5437
        $sql = "SELECT url, description, active, created_by, tms
5438
                FROM $table_access_url WHERE id = '$id' ";
5439
        $res = Database::query($sql);
5440
        $result = @Database::fetch_array($res);
5441
        $staticResult[$id] = $result;
5442
    }
5443
5444
    // If the result url is 'http://localhost/' (the default) and the root_web
5445
    // (=current url) is different, and the $id is = 1 (which might mean
5446
    // api_get_current_access_url_id() returned 1 by default), then return the
5447
    // root_web setting instead of the current URL
5448
    // This is provided as an option to avoid breaking the storage of URL-specific
5449
    // homepages in home/localhost/
5450
    if (1 === $id && false === $returnDefault) {
5451
        $currentUrl = api_get_current_access_url_id();
5452
        // only do this if we are on the main URL (=1), otherwise we could get
5453
        // information on another URL instead of the one asked as parameter
5454
        if (1 === $currentUrl) {
5455
            $rootWeb = api_get_path(WEB_PATH);
5456
            $default = 'http://localhost/';
5457
            if ($result['url'] === $default && $rootWeb != $default) {
5458
                $result['url'] = $rootWeb;
5459
            }
5460
        }
5461
    }
5462
5463
    return $result;
5464
}
5465
5466
/**
5467
 * Gets all the current settings for a specific access url.
5468
 *
5469
 * @param string    The category, if any, that we want to get
5470
 * @param string    Whether we want a simple list (display a category) or
5471
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5472
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5473
 *
5474
 * @return array Array of database results for the current settings of the current access URL
5475
 */
5476
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5477
{
5478
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5479
    $access_url = (int) $access_url;
5480
    $where_condition = '';
5481
    if (1 == $url_changeable) {
5482
        $where_condition = " AND access_url_changeable= '1' ";
5483
    }
5484
    if (empty($access_url) || -1 == $access_url) {
5485
        $access_url = 1;
5486
    }
5487
    $sql = "SELECT * FROM $table
5488
            WHERE access_url = $access_url  $where_condition ";
5489
5490
    if (!empty($cat)) {
5491
        $cat = Database::escape_string($cat);
5492
        $sql .= " AND category='$cat' ";
5493
    }
5494
    if ('group' == $ordering) {
5495
        $sql .= " ORDER BY id ASC";
5496
    } else {
5497
        $sql .= " ORDER BY 1,2 ASC";
5498
    }
5499
    $result = Database::query($sql);
5500
    if (null === $result) {
5501
        return [];
5502
    }
5503
    $result = Database::store_result($result, 'ASSOC');
5504
5505
    return $result;
5506
}
5507
5508
/**
5509
 * @param string $value       The value we want to record
5510
 * @param string $variable    The variable name we want to insert
5511
 * @param string $subKey      The subkey for the variable we want to insert
5512
 * @param string $type        The type for the variable we want to insert
5513
 * @param string $category    The category for the variable we want to insert
5514
 * @param string $title       The title
5515
 * @param string $comment     The comment
5516
 * @param string $scope       The scope
5517
 * @param string $subKeyText  The subkey text
5518
 * @param int    $accessUrlId The access_url for which this parameter is valid
5519
 * @param int    $visibility  The changeability of this setting for non-master urls
5520
 *
5521
 * @return int The setting ID
5522
 */
5523
function api_add_setting(
5524
    $value,
5525
    $variable,
5526
    $subKey = '',
5527
    $type = 'textfield',
5528
    $category = '',
5529
    $title = '',
5530
    $comment = '',
5531
    $scope = '',
5532
    $subKeyText = '',
5533
    $accessUrlId = 1,
5534
    $visibility = 0
5535
) {
5536
    $em = Database::getManager();
5537
5538
    $settingRepo = $em->getRepository(SettingsCurrent::class);
5539
    $accessUrlId = (int) $accessUrlId ?: 1;
5540
5541
    if (is_array($value)) {
5542
        $value = serialize($value);
5543
    } else {
5544
        $value = trim($value);
5545
    }
5546
5547
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5548
5549
    if (!empty($subKey)) {
5550
        $criteria['subkey'] = $subKey;
5551
    }
5552
5553
    // Check if this variable doesn't exist already
5554
    /** @var SettingsCurrent $setting */
5555
    $setting = $settingRepo->findOneBy($criteria);
5556
5557
    if ($setting) {
5558
        $setting->setSelectedValue($value);
5559
5560
        $em->persist($setting);
5561
        $em->flush();
5562
5563
        return $setting->getId();
5564
    }
5565
5566
    // Item not found for this access_url, we have to check if the whole thing is missing
5567
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5568
    $setting = new SettingsCurrent();
5569
    $url = api_get_url_entity();
5570
5571
    $setting
5572
        ->setVariable($variable)
5573
        ->setSelectedValue($value)
5574
        ->setType($type)
5575
        ->setCategory($category)
5576
        ->setSubkey($subKey)
5577
        ->setTitle($title)
5578
        ->setComment($comment)
5579
        ->setScope($scope)
5580
        ->setSubkeytext($subKeyText)
5581
        ->setUrl(api_get_url_entity())
5582
        ->setAccessUrlChangeable($visibility);
5583
5584
    $em->persist($setting);
5585
    $em->flush();
5586
5587
    return $setting->getId();
5588
}
5589
5590
/**
5591
 * Checks wether a user can or can't view the contents of a course.
5592
 *
5593
 * @deprecated use CourseManager::is_user_subscribed_in_course
5594
 *
5595
 * @param int $userid User id or NULL to get it from $_SESSION
5596
 * @param int $cid    course id to check whether the user is allowed
5597
 *
5598
 * @return bool
5599
 */
5600
function api_is_course_visible_for_user($userid = null, $cid = null)
5601
{
5602
    if (null === $userid) {
5603
        $userid = api_get_user_id();
5604
    }
5605
    if (empty($userid) || strval(intval($userid)) != $userid) {
5606
        if (api_is_anonymous()) {
5607
            $userid = api_get_anonymous_id();
5608
        } else {
5609
            return false;
5610
        }
5611
    }
5612
    $cid = Database::escape_string($cid);
5613
5614
    $courseInfo = api_get_course_info($cid);
5615
    $courseId = $courseInfo['real_id'];
5616
    $is_platformAdmin = api_is_platform_admin();
5617
5618
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5619
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5620
5621
    $sql = "SELECT
5622
                $course_cat_table.code AS category_code,
5623
                $course_table.visibility,
5624
                $course_table.code,
5625
                $course_cat_table.code
5626
            FROM $course_table
5627
            LEFT JOIN $course_cat_table
5628
                ON $course_table.category_id = $course_cat_table.id
5629
            WHERE
5630
                $course_table.code = '$cid'
5631
            LIMIT 1";
5632
5633
    $result = Database::query($sql);
5634
5635
    if (Database::num_rows($result) > 0) {
5636
        $visibility = Database::fetch_array($result);
5637
        $visibility = $visibility['visibility'];
5638
    } else {
5639
        $visibility = 0;
5640
    }
5641
    // Shortcut permissions in case the visibility is "open to the world".
5642
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5643
        return true;
5644
    }
5645
5646
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5647
5648
    $sql = "SELECT
5649
                is_tutor, status
5650
            FROM $tbl_course_user
5651
            WHERE
5652
                user_id  = '$userid' AND
5653
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5654
                c_id = $courseId
5655
            LIMIT 1";
5656
5657
    $result = Database::query($sql);
5658
5659
    if (Database::num_rows($result) > 0) {
5660
        // This user has got a recorded state for this course.
5661
        $cuData = Database::fetch_array($result);
5662
        $is_courseMember = true;
5663
        $is_courseAdmin = (1 == $cuData['status']);
5664
    }
5665
5666
    if (!$is_courseAdmin) {
5667
        // This user has no status related to this course.
5668
        // Is it the session coach or the session admin?
5669
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5670
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5671
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5672
5673
        $sql = "SELECT
5674
                    session.id_coach, session_admin_id, session.id
5675
                FROM
5676
                    $tbl_session as session
5677
                INNER JOIN $tbl_session_course
5678
                    ON session_rel_course.session_id = session.id
5679
                    AND session_rel_course.c_id = '$courseId'
5680
                LIMIT 1";
5681
5682
        $result = Database::query($sql);
5683
        $row = Database::store_result($result);
5684
5685
        if ($row[0]['id_coach'] == $userid) {
5686
            $is_courseMember = true;
5687
            $is_courseAdmin = false;
5688
        } elseif ($row[0]['session_admin_id'] == $userid) {
5689
            $is_courseMember = false;
5690
            $is_courseAdmin = false;
5691
        } else {
5692
            // Check if the current user is the course coach.
5693
            $sql = "SELECT 1
5694
                    FROM $tbl_session_course
5695
                    WHERE session_rel_course.c_id = '$courseId'
5696
                    AND session_rel_course.id_coach = '$userid'
5697
                    LIMIT 1";
5698
5699
            $result = Database::query($sql);
5700
5701
            //if ($row = Database::fetch_array($result)) {
5702
            if (Database::num_rows($result) > 0) {
5703
                $is_courseMember = true;
5704
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5705
5706
                $sql = "SELECT status FROM $tbl_user
5707
                        WHERE id = $userid
5708
                        LIMIT 1";
5709
5710
                $result = Database::query($sql);
5711
5712
                if (1 == Database::result($result, 0, 0)) {
5713
                    $is_courseAdmin = true;
5714
                } else {
5715
                    $is_courseAdmin = false;
5716
                }
5717
            } else {
5718
                // Check if the user is a student is this session.
5719
                $sql = "SELECT  id
5720
                        FROM $tbl_session_course_user
5721
                        WHERE
5722
                            user_id  = '$userid' AND
5723
                            c_id = '$courseId'
5724
                        LIMIT 1";
5725
5726
                if (Database::num_rows($result) > 0) {
5727
                    // This user haa got a recorded state for this course.
5728
                    while ($row = Database::fetch_array($result)) {
5729
                        $is_courseMember = true;
5730
                        $is_courseAdmin = false;
5731
                    }
5732
                }
5733
            }
5734
        }
5735
    }
5736
5737
    switch ($visibility) {
5738
        case COURSE_VISIBILITY_OPEN_WORLD:
5739
            return true;
5740
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5741
            return isset($userid);
5742
        case COURSE_VISIBILITY_REGISTERED:
5743
        case COURSE_VISIBILITY_CLOSED:
5744
            return $is_platformAdmin || $is_courseMember || $is_courseAdmin;
5745
        case COURSE_VISIBILITY_HIDDEN:
5746
            return $is_platformAdmin;
5747
    }
5748
5749
    return false;
5750
}
5751
5752
/**
5753
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5754
 *
5755
 * @param string the tool of the element
5756
 * @param int the element id in database
5757
 * @param int the session_id to compare with element session id
5758
 *
5759
 * @return bool true if the element is in the session, false else
5760
 */
5761
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5762
{
5763
    if (is_null($session_id)) {
5764
        $session_id = api_get_session_id();
5765
    }
5766
5767
    $element_id = (int) $element_id;
5768
5769
    if (empty($element_id)) {
5770
        return false;
5771
    }
5772
5773
    // Get information to build query depending of the tool.
5774
    switch ($tool) {
5775
        case TOOL_SURVEY:
5776
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5777
            $key_field = 'survey_id';
5778
            break;
5779
        case TOOL_ANNOUNCEMENT:
5780
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5781
            $key_field = 'id';
5782
            break;
5783
        case TOOL_AGENDA:
5784
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5785
            $key_field = 'id';
5786
            break;
5787
        case TOOL_GROUP:
5788
            $table_tool = Database::get_course_table(TABLE_GROUP);
5789
            $key_field = 'id';
5790
            break;
5791
        default:
5792
            return false;
5793
    }
5794
    $course_id = api_get_course_int_id();
5795
5796
    $sql = "SELECT session_id FROM $table_tool
5797
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5798
    $rs = Database::query($sql);
5799
    if ($element_session_id = Database::result($rs, 0, 0)) {
5800
        if ($element_session_id == intval($session_id)) {
5801
            // The element belongs to the session.
5802
            return true;
5803
        }
5804
    }
5805
5806
    return false;
5807
}
5808
5809
/**
5810
 * Replaces "forbidden" characters in a filename string.
5811
 *
5812
 * @param string $filename
5813
 * @param bool   $treat_spaces_as_hyphens
5814
 *
5815
 * @return string
5816
 */
5817
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5818
{
5819
    // Some non-properly encoded file names can cause the whole file to be
5820
    // skipped when uploaded. Avoid this by detecting the encoding and
5821
    // converting to UTF-8, setting the source as ASCII (a reasonably
5822
    // limited characters set) if nothing could be found (BT#
5823
    $encoding = api_detect_encoding($filename);
5824
    if (empty($encoding)) {
5825
        $encoding = 'ASCII';
5826
        if (!api_is_valid_ascii($filename)) {
5827
            // try iconv and try non standard ASCII a.k.a CP437
5828
            // see BT#15022
5829
            if (function_exists('iconv')) {
5830
                $result = iconv('CP437', 'UTF-8', $filename);
5831
                if (api_is_valid_utf8($result)) {
5832
                    $filename = $result;
5833
                    $encoding = 'UTF-8';
5834
                }
5835
            }
5836
        }
5837
    }
5838
5839
    $filename = api_to_system_encoding($filename, $encoding);
5840
5841
    $url = URLify::filter(
5842
        $filename,
5843
        250,
5844
        '',
5845
        true,
5846
        false,
5847
        false,
5848
        false
5849
    );
5850
5851
    return $url;
5852
}
5853
5854
/**
5855
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5856
 *
5857
 * @author Ivan Tcholakov, 28-JUN-2006.
5858
 */
5859
function api_request_uri()
5860
{
5861
    if (!empty($_SERVER['REQUEST_URI'])) {
5862
        return $_SERVER['REQUEST_URI'];
5863
    }
5864
    $uri = $_SERVER['SCRIPT_NAME'];
5865
    if (!empty($_SERVER['QUERY_STRING'])) {
5866
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5867
    }
5868
    $_SERVER['REQUEST_URI'] = $uri;
5869
5870
    return $uri;
5871
}
5872
5873
/** Gets the current access_url id of the Chamilo Platform.
5874
 * @author Julio Montoya <[email protected]>
5875
 *
5876
 * @return int access_url_id of the current Chamilo Installation
5877
 */
5878
function api_get_current_access_url_id()
5879
{
5880
    if (false === api_get_multiple_access_url()) {
5881
        return 1;
5882
    }
5883
5884
    static $id;
5885
    if (!empty($id)) {
5886
        return $id;
5887
    }
5888
5889
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5890
    $path = Database::escape_string(api_get_path(WEB_PATH));
5891
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5892
    $result = Database::query($sql);
5893
    if (Database::num_rows($result) > 0) {
5894
        $id = Database::result($result, 0, 0);
5895
        if (false === $id) {
5896
            return -1;
5897
        }
5898
5899
        return (int) $id;
5900
    }
5901
5902
    $id = 1;
5903
5904
    //if the url in WEB_PATH was not found, it can only mean that there is
5905
    // either a configuration problem or the first URL has not been defined yet
5906
    // (by default it is http://localhost/). Thus the more sensible thing we can
5907
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5908
    return 1;
5909
}
5910
5911
/**
5912
 * Gets the registered urls from a given user id.
5913
 *
5914
 * @author Julio Montoya <[email protected]>
5915
 *
5916
 * @param int $user_id
5917
 *
5918
 * @return array
5919
 */
5920
function api_get_access_url_from_user($user_id)
5921
{
5922
    $user_id = (int) $user_id;
5923
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5924
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5925
    $sql = "SELECT access_url_id
5926
            FROM $table_url_rel_user url_rel_user
5927
            INNER JOIN $table_url u
5928
            ON (url_rel_user.access_url_id = u.id)
5929
            WHERE user_id = ".$user_id;
5930
    $result = Database::query($sql);
5931
    $list = [];
5932
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5933
        $list[] = $row['access_url_id'];
5934
    }
5935
5936
    return $list;
5937
}
5938
5939
/**
5940
 * Checks whether the curent user is in a group or not.
5941
 *
5942
 * @param string        The group id - optional (takes it from session if not given)
5943
 * @param string        The course code - optional (no additional check by course if course code is not given)
5944
 *
5945
 * @return bool
5946
 *
5947
 * @author Ivan Tcholakov
5948
 */
5949
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5950
{
5951
    if (!empty($courseCodeParam)) {
5952
        $courseCode = api_get_course_id();
5953
        if (!empty($courseCode)) {
5954
            if ($courseCodeParam != $courseCode) {
5955
                return false;
5956
            }
5957
        } else {
5958
            return false;
5959
        }
5960
    }
5961
5962
    $groupId = api_get_group_id();
5963
5964
    if (isset($groupId) && '' != $groupId) {
5965
        if (!empty($groupIdParam)) {
5966
            return $groupIdParam == $groupId;
5967
        } else {
5968
            return true;
5969
        }
5970
    }
5971
5972
    return false;
5973
}
5974
5975
/**
5976
 * Checks whether a secret key is valid.
5977
 *
5978
 * @param string $original_key_secret - secret key from (webservice) client
5979
 * @param string $security_key        - security key from Chamilo
5980
 *
5981
 * @return bool - true if secret key is valid, false otherwise
5982
 */
5983
function api_is_valid_secret_key($original_key_secret, $security_key)
5984
{
5985
    return $original_key_secret == sha1($security_key);
5986
}
5987
5988
/**
5989
 * Checks whether a user is into course.
5990
 *
5991
 * @param int $course_id - the course id
5992
 * @param int $user_id   - the user id
5993
 *
5994
 * @return bool
5995
 */
5996
function api_is_user_of_course($course_id, $user_id)
5997
{
5998
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5999
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6000
            WHERE
6001
                c_id ="'.intval($course_id).'" AND
6002
                user_id = "'.intval($user_id).'" AND
6003
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6004
    $result = Database::query($sql);
6005
6006
    return 1 == Database::num_rows($result);
6007
}
6008
6009
/**
6010
 * Checks whether the server's operating system is Windows (TM).
6011
 *
6012
 * @return bool - true if the operating system is Windows, false otherwise
6013
 */
6014
function api_is_windows_os()
6015
{
6016
    if (function_exists('php_uname')) {
6017
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6018
        // We expect that this function will always work for Chamilo 1.8.x.
6019
        $os = php_uname();
6020
    }
6021
    // The following methods are not needed, but let them stay, just in case.
6022
    elseif (isset($_ENV['OS'])) {
6023
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6024
        $os = $_ENV['OS'];
6025
    } elseif (defined('PHP_OS')) {
6026
        // PHP_OS means on which OS PHP was compiled, this is why
6027
        // using PHP_OS is the last choice for detection.
6028
        $os = PHP_OS;
6029
    } else {
6030
        return false;
6031
    }
6032
6033
    return 'win' == strtolower(substr((string) $os, 0, 3));
6034
}
6035
6036
/**
6037
 * This function informs whether the sent request is XMLHttpRequest.
6038
 */
6039
function api_is_xml_http_request()
6040
{
6041
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
6042
}
6043
6044
/**
6045
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6046
 *
6047
 * @see http://php.net/manual/en/function.getimagesize.php
6048
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6049
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6050
 *
6051
 * @return int
6052
 */
6053
function api_getimagesize($path)
6054
{
6055
    $image = new Image($path);
6056
6057
    return $image->get_image_size();
6058
}
6059
6060
/**
6061
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6062
 *
6063
 * @author Ivan Tcholakov, MAY-2009.
6064
 *
6065
 * @param int $image         System path or URL of the image
6066
 * @param int $target_width  Targeted width
6067
 * @param int $target_height Targeted height
6068
 *
6069
 * @return array Calculated new width and height
6070
 */
6071
function api_resize_image($image, $target_width, $target_height)
6072
{
6073
    $image_properties = api_getimagesize($image);
6074
6075
    return api_calculate_image_size(
6076
        $image_properties['width'],
6077
        $image_properties['height'],
6078
        $target_width,
6079
        $target_height
6080
    );
6081
}
6082
6083
/**
6084
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6085
 *
6086
 * @author Ivan Tcholakov, MAY-2009.
6087
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6088
 *
6089
 * @param int $image_width   Initial width
6090
 * @param int $image_height  Initial height
6091
 * @param int $target_width  Targeted width
6092
 * @param int $target_height Targeted height
6093
 *
6094
 * @return array Calculated new width and height
6095
 */
6096
function api_calculate_image_size(
6097
    $image_width,
6098
    $image_height,
6099
    $target_width,
6100
    $target_height
6101
) {
6102
    // Only maths is here.
6103
    $result = ['width' => $image_width, 'height' => $image_height];
6104
    if ($image_width <= 0 || $image_height <= 0) {
6105
        return $result;
6106
    }
6107
    $resize_factor_width = $target_width / $image_width;
6108
    $resize_factor_height = $target_height / $image_height;
6109
    $delta_width = $target_width - $image_width * $resize_factor_height;
6110
    $delta_height = $target_height - $image_height * $resize_factor_width;
6111
    if ($delta_width > $delta_height) {
6112
        $result['width'] = ceil($image_width * $resize_factor_height);
6113
        $result['height'] = ceil($image_height * $resize_factor_height);
6114
    } elseif ($delta_width < $delta_height) {
6115
        $result['width'] = ceil($image_width * $resize_factor_width);
6116
        $result['height'] = ceil($image_height * $resize_factor_width);
6117
    } else {
6118
        $result['width'] = ceil($target_width);
6119
        $result['height'] = ceil($target_height);
6120
    }
6121
6122
    return $result;
6123
}
6124
6125
/**
6126
 * Returns a list of Chamilo's tools or
6127
 * checks whether a given identificator is a valid Chamilo's tool.
6128
 *
6129
 * @author Isaac flores paz
6130
 *
6131
 * @param string The tool name to filter
6132
 *
6133
 * @return mixed Filtered string or array
6134
 */
6135
function api_get_tools_lists($my_tool = null)
6136
{
6137
    $tools_list = [
6138
        TOOL_DOCUMENT,
6139
        TOOL_THUMBNAIL,
6140
        TOOL_HOTPOTATOES,
6141
        TOOL_CALENDAR_EVENT,
6142
        TOOL_LINK,
6143
        TOOL_COURSE_DESCRIPTION,
6144
        TOOL_SEARCH,
6145
        TOOL_LEARNPATH,
6146
        TOOL_ANNOUNCEMENT,
6147
        TOOL_FORUM,
6148
        TOOL_THREAD,
6149
        TOOL_POST,
6150
        TOOL_DROPBOX,
6151
        TOOL_QUIZ,
6152
        TOOL_USER,
6153
        TOOL_GROUP,
6154
        TOOL_BLOGS,
6155
        TOOL_CHAT,
6156
        TOOL_STUDENTPUBLICATION,
6157
        TOOL_TRACKING,
6158
        TOOL_HOMEPAGE_LINK,
6159
        TOOL_COURSE_SETTING,
6160
        TOOL_BACKUP,
6161
        TOOL_COPY_COURSE_CONTENT,
6162
        TOOL_RECYCLE_COURSE,
6163
        TOOL_COURSE_HOMEPAGE,
6164
        TOOL_COURSE_RIGHTS_OVERVIEW,
6165
        TOOL_UPLOAD,
6166
        TOOL_COURSE_MAINTENANCE,
6167
        TOOL_SURVEY,
6168
        TOOL_WIKI,
6169
        TOOL_GLOSSARY,
6170
        TOOL_GRADEBOOK,
6171
        TOOL_NOTEBOOK,
6172
        TOOL_ATTENDANCE,
6173
        TOOL_COURSE_PROGRESS,
6174
    ];
6175
    if (empty($my_tool)) {
6176
        return $tools_list;
6177
    }
6178
6179
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6180
}
6181
6182
/**
6183
 * Checks whether we already approved the last version term and condition.
6184
 *
6185
 * @param int user id
6186
 *
6187
 * @return bool true if we pass false otherwise
6188
 */
6189
function api_check_term_condition($userId)
6190
{
6191
    if ('true' === api_get_setting('allow_terms_conditions')) {
6192
        // Check if exists terms and conditions
6193
        if (0 == LegalManager::count()) {
6194
            return true;
6195
        }
6196
6197
        $extraFieldValue = new ExtraFieldValue('user');
6198
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6199
            $userId,
6200
            'legal_accept'
6201
        );
6202
6203
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6204
            $result = $data['value'];
6205
            $user_conditions = explode(':', $result);
6206
            $version = $user_conditions[0];
6207
            $langId = $user_conditions[1];
6208
            $realVersion = LegalManager::get_last_version($langId);
6209
6210
            return $version >= $realVersion;
6211
        }
6212
6213
        return false;
6214
    }
6215
6216
    return false;
6217
}
6218
6219
/**
6220
 * Gets all information of a tool into course.
6221
 *
6222
 * @param int The tool id
6223
 *
6224
 * @return array
6225
 */
6226
function api_get_tool_information_by_name($name)
6227
{
6228
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6229
    $course_id = api_get_course_int_id();
6230
6231
    $sql = "SELECT id FROM tool
6232
            WHERE name = '".Database::escape_string($name)."' ";
6233
    $rs = Database::query($sql);
6234
    $data = Database::fetch_array($rs);
6235
    $tool = $data['id'];
6236
6237
    $sql = "SELECT * FROM $t_tool
6238
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6239
    $rs = Database::query($sql);
6240
6241
    return Database::fetch_array($rs, 'ASSOC');
6242
}
6243
6244
/**
6245
 * Function used to protect a "global" admin script.
6246
 * The function blocks access when the user has no global platform admin rights.
6247
 * Global admins are the admins that are registered in the main.admin table
6248
 * AND the users who have access to the "principal" portal.
6249
 * That means that there is a record in the main.access_url_rel_user table
6250
 * with his user id and the access_url_id=1.
6251
 *
6252
 * @author Julio Montoya
6253
 *
6254
 * @param int $user_id
6255
 *
6256
 * @return bool
6257
 */
6258
function api_is_global_platform_admin($user_id = null)
6259
{
6260
    $user_id = (int) $user_id;
6261
    if (empty($user_id)) {
6262
        $user_id = api_get_user_id();
6263
    }
6264
    if (api_is_platform_admin_by_id($user_id)) {
6265
        $urlList = api_get_access_url_from_user($user_id);
6266
        // The admin is registered in the first "main" site with access_url_id = 1
6267
        if (in_array(1, $urlList)) {
6268
            return true;
6269
        } else {
6270
            return false;
6271
        }
6272
    }
6273
6274
    return false;
6275
}
6276
6277
/**
6278
 * @param int  $admin_id_to_check
6279
 * @param int  $my_user_id
6280
 * @param bool $allow_session_admin
6281
 *
6282
 * @return bool
6283
 */
6284
function api_global_admin_can_edit_admin(
6285
    $admin_id_to_check,
6286
    $my_user_id = null,
6287
    $allow_session_admin = false
6288
) {
6289
    if (empty($my_user_id)) {
6290
        $my_user_id = api_get_user_id();
6291
    }
6292
6293
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6294
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6295
6296
    if ($iam_a_global_admin) {
6297
        // Global admin can edit everything
6298
        return true;
6299
    } else {
6300
        // If i'm a simple admin
6301
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6302
6303
        if ($allow_session_admin) {
6304
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
6305
        }
6306
6307
        if ($is_platform_admin) {
6308
            if ($user_is_global_admin) {
6309
                return false;
6310
            } else {
6311
                return true;
6312
            }
6313
        } else {
6314
            return false;
6315
        }
6316
    }
6317
}
6318
6319
/**
6320
 * @param int  $admin_id_to_check
6321
 * @param int  $my_user_id
6322
 * @param bool $allow_session_admin
6323
 *
6324
 * @return bool|null
6325
 */
6326
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6327
{
6328
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6329
        return true;
6330
    } else {
6331
        api_not_allowed();
6332
    }
6333
}
6334
6335
/**
6336
 * Function used to protect a global admin script.
6337
 * The function blocks access when the user has no global platform admin rights.
6338
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6339
 *
6340
 * @author Julio Montoya
6341
 */
6342
function api_protect_global_admin_script()
6343
{
6344
    if (!api_is_global_platform_admin()) {
6345
        api_not_allowed();
6346
6347
        return false;
6348
    }
6349
6350
    return true;
6351
}
6352
6353
/**
6354
 * Check browser support for specific file types or features
6355
 * This function checks if the user's browser supports a file format or given
6356
 * feature, or returns the current browser and major version when
6357
 * $format=check_browser. Only a limited number of formats and features are
6358
 * checked by this method. Make sure you check its definition first.
6359
 *
6360
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6361
 *
6362
 * @deprecated
6363
 *
6364
 * @return bool or return text array if $format=check_browser
6365
 *
6366
 * @author Juan Carlos Raña Trabado
6367
 */
6368
function api_browser_support($format = '')
6369
{
6370
    return true;
6371
6372
    $browser = new Browser();
6373
    $current_browser = $browser->getBrowser();
6374
    $a_versiontemp = explode('.', $browser->getVersion());
6375
    $current_majorver = $a_versiontemp[0];
6376
6377
    static $result;
6378
6379
    if (isset($result[$format])) {
6380
        return $result[$format];
6381
    }
6382
6383
    // Native svg support
6384
    if ('svg' == $format) {
6385
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6386
            ('Firefox' == $current_browser && $current_majorver > 1) ||
6387
            ('Safari' == $current_browser && $current_majorver >= 4) ||
6388
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
6389
            ('Opera' == $current_browser && $current_majorver >= 9)
6390
        ) {
6391
            $result[$format] = true;
6392
6393
            return true;
6394
        } else {
6395
            $result[$format] = false;
6396
6397
            return false;
6398
        }
6399
    } elseif ('pdf' == $format) {
6400
        // native pdf support
6401
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6402
            $result[$format] = true;
6403
6404
            return true;
6405
        } else {
6406
            $result[$format] = false;
6407
6408
            return false;
6409
        }
6410
    } elseif ('tif' == $format || 'tiff' == $format) {
6411
        //native tif support
6412
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6413
            $result[$format] = true;
6414
6415
            return true;
6416
        } else {
6417
            $result[$format] = false;
6418
6419
            return false;
6420
        }
6421
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6422
        //native ogg, ogv,oga support
6423
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6424
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6425
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6426
            $result[$format] = true;
6427
6428
            return true;
6429
        } else {
6430
            $result[$format] = false;
6431
6432
            return false;
6433
        }
6434
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6435
        //native mpg support
6436
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6437
            $result[$format] = true;
6438
6439
            return true;
6440
        } else {
6441
            $result[$format] = false;
6442
6443
            return false;
6444
        }
6445
    } elseif ('mp4' == $format) {
6446
        //native mp4 support (TODO: Android, iPhone)
6447
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6448
            $result[$format] = true;
6449
6450
            return true;
6451
        } else {
6452
            $result[$format] = false;
6453
6454
            return false;
6455
        }
6456
    } elseif ('mov' == $format) {
6457
        //native mov support( TODO:check iPhone)
6458
        if ('Safari' == $current_browser && $current_majorver >= 5 || 'iPhone' == $current_browser) {
6459
            $result[$format] = true;
6460
6461
            return true;
6462
        } else {
6463
            $result[$format] = false;
6464
6465
            return false;
6466
        }
6467
    } elseif ('avi' == $format) {
6468
        //native avi support
6469
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6470
            $result[$format] = true;
6471
6472
            return true;
6473
        } else {
6474
            $result[$format] = false;
6475
6476
            return false;
6477
        }
6478
    } elseif ('wmv' == $format) {
6479
        //native wmv support
6480
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6481
            $result[$format] = true;
6482
6483
            return true;
6484
        } else {
6485
            $result[$format] = false;
6486
6487
            return false;
6488
        }
6489
    } elseif ('webm' == $format) {
6490
        //native webm support (TODO:check IE9, Chrome9, Android)
6491
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6492
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6493
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6494
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6495
            'Android' == $current_browser
6496
        ) {
6497
            $result[$format] = true;
6498
6499
            return true;
6500
        } else {
6501
            $result[$format] = false;
6502
6503
            return false;
6504
        }
6505
    } elseif ('wav' == $format) {
6506
        //native wav support (only some codecs !)
6507
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6508
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6509
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6510
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6511
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6512
            'Android' == $current_browser ||
6513
            'iPhone' == $current_browser
6514
        ) {
6515
            $result[$format] = true;
6516
6517
            return true;
6518
        } else {
6519
            $result[$format] = false;
6520
6521
            return false;
6522
        }
6523
    } elseif ('mid' == $format || 'kar' == $format) {
6524
        //native midi support (TODO:check Android)
6525
        if ('Opera' == $current_browser && $current_majorver >= 9 || 'Android' == $current_browser) {
6526
            $result[$format] = true;
6527
6528
            return true;
6529
        } else {
6530
            $result[$format] = false;
6531
6532
            return false;
6533
        }
6534
    } elseif ('wma' == $format) {
6535
        //native wma support
6536
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6537
            $result[$format] = true;
6538
6539
            return true;
6540
        } else {
6541
            $result[$format] = false;
6542
6543
            return false;
6544
        }
6545
    } elseif ('au' == $format) {
6546
        //native au support
6547
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6548
            $result[$format] = true;
6549
6550
            return true;
6551
        } else {
6552
            $result[$format] = false;
6553
6554
            return false;
6555
        }
6556
    } elseif ('mp3' == $format) {
6557
        //native mp3 support (TODO:check Android, iPhone)
6558
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
6559
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
6560
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6561
            'Android' == $current_browser ||
6562
            'iPhone' == $current_browser ||
6563
            'Firefox' == $current_browser
6564
        ) {
6565
            $result[$format] = true;
6566
6567
            return true;
6568
        } else {
6569
            $result[$format] = false;
6570
6571
            return false;
6572
        }
6573
    } elseif ('autocapitalize' == $format) {
6574
        // Help avoiding showing the autocapitalize option if the browser doesn't
6575
        // support it: this attribute is against the HTML5 standard
6576
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
6577
            return true;
6578
        } else {
6579
            return false;
6580
        }
6581
    } elseif ("check_browser" == $format) {
6582
        $array_check_browser = [$current_browser, $current_majorver];
6583
6584
        return $array_check_browser;
6585
    } else {
6586
        $result[$format] = false;
6587
6588
        return false;
6589
    }
6590
}
6591
6592
/**
6593
 * This function checks if exist path and file browscap.ini
6594
 * In order for this to work, your browscap configuration setting in php.ini
6595
 * must point to the correct location of the browscap.ini file on your system
6596
 * http://php.net/manual/en/function.get-browser.php.
6597
 *
6598
 * @return bool
6599
 *
6600
 * @author Juan Carlos Raña Trabado
6601
 */
6602
function api_check_browscap()
6603
{
6604
    $setting = ini_get('browscap');
6605
    if ($setting) {
6606
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6607
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6608
            return true;
6609
        }
6610
    }
6611
6612
    return false;
6613
}
6614
6615
/**
6616
 * Returns the <script> HTML tag.
6617
 */
6618
function api_get_js($file)
6619
{
6620
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6621
}
6622
6623
function api_get_build_js($file)
6624
{
6625
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6626
}
6627
6628
function api_get_build_css($file, $media = 'screen')
6629
{
6630
    return '<link
6631
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6632
}
6633
6634
/**
6635
 * Returns the <script> HTML tag.
6636
 *
6637
 * @return string
6638
 */
6639
function api_get_asset($file)
6640
{
6641
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6642
}
6643
6644
/**
6645
 * Returns the <script> HTML tag.
6646
 *
6647
 * @param string $file
6648
 * @param string $media
6649
 *
6650
 * @return string
6651
 */
6652
function api_get_css_asset($file, $media = 'screen')
6653
{
6654
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6655
}
6656
6657
/**
6658
 * Returns the <link> HTML tag.
6659
 *
6660
 * @param string $file
6661
 * @param string $media
6662
 */
6663
function api_get_css($file, $media = 'screen')
6664
{
6665
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6666
}
6667
6668
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
6669
{
6670
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6671
    if ($returnOnlyPath) {
6672
        return $url;
6673
    }
6674
6675
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
6676
}
6677
6678
/**
6679
 * Returns the js header to include the jquery library.
6680
 */
6681
function api_get_jquery_js()
6682
{
6683
    return api_get_asset('jquery/jquery.min.js');
6684
}
6685
6686
/**
6687
 * Returns the jquery path.
6688
 *
6689
 * @return string
6690
 */
6691
function api_get_jquery_web_path()
6692
{
6693
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
6694
}
6695
6696
/**
6697
 * @return string
6698
 */
6699
function api_get_jquery_ui_js_web_path()
6700
{
6701
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6702
}
6703
6704
/**
6705
 * @return string
6706
 */
6707
function api_get_jquery_ui_css_web_path()
6708
{
6709
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6710
}
6711
6712
/**
6713
 * Returns the jquery-ui library js headers.
6714
 *
6715
 * @return string html tags
6716
 */
6717
function api_get_jquery_ui_js()
6718
{
6719
    $libraries = [];
6720
6721
    return api_get_jquery_libraries_js($libraries);
6722
}
6723
6724
function api_get_jqgrid_js()
6725
{
6726
    $routePublic = Container::getRouter()->generate('home');
6727
6728
    return api_get_css($routePublic.'build/free-jqgrid.css').PHP_EOL
6729
        .api_get_js_simple($routePublic.'build/free-jqgrid.js');
6730
}
6731
6732
/**
6733
 * Returns the jquery library js and css headers.
6734
 *
6735
 * @param   array   list of jquery libraries supported jquery-ui
6736
 * @param   bool    add the jquery library
6737
 *
6738
 * @return string html tags
6739
 */
6740
function api_get_jquery_libraries_js($libraries)
6741
{
6742
    $js = '';
6743
6744
    //Document multiple upload funcionality
6745
    if (in_array('jquery-uploadzs', $libraries)) {
6746
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6747
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6748
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6749
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6750
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6751
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6752
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6753
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6754
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6755
6756
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6757
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6758
    }
6759
6760
    // jquery datepicker
6761
    if (in_array('datepicker', $libraries)) {
6762
        $languaje = 'en-GB';
6763
        $platform_isocode = strtolower(api_get_language_isocode());
6764
6765
        $datapicker_langs = [
6766
            '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',
6767
        ];
6768
        if (in_array($platform_isocode, $datapicker_langs)) {
6769
            $languaje = $platform_isocode;
6770
        }
6771
6772
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6773
        $script = '<script>
6774
        $(function(){
6775
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6776
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6777
        });
6778
        </script>
6779
        ';
6780
        $js .= $script;
6781
    }
6782
6783
    return $js;
6784
}
6785
6786
/**
6787
 * Returns the URL to the course or session, removing the complexity of the URL
6788
 * building piece by piece.
6789
 *
6790
 * This function relies on api_get_course_info()
6791
 *
6792
 * @param string $courseCode The course code - optional (takes it from context if not given)
6793
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
6794
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
6795
 *
6796
 * @return string The URL to a course, a session, or empty string if nothing works
6797
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
6798
 *
6799
 * @author  Julio Montoya <[email protected]>
6800
 */
6801
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
6802
{
6803
    $url = '';
6804
    // If courseCode not set, get context or []
6805
    if (empty($courseCode)) {
6806
        $courseInfo = api_get_course_info();
6807
    } else {
6808
        $courseInfo = api_get_course_info($courseCode);
6809
    }
6810
6811
    // If sessionId not set, get context or 0
6812
    if (empty($sessionId)) {
6813
        $sessionId = api_get_session_id();
6814
    }
6815
6816
    // If groupId not set, get context or 0
6817
    if (empty($groupId)) {
6818
        $groupId = api_get_group_id();
6819
    }
6820
6821
    // Build the URL
6822
    if (!empty($courseInfo)) {
6823
        // directory not empty, so we do have a course
6824
        $url = $courseInfo['course_public_url'].'?sid='.$sessionId.'&gid='.$groupId;
6825
    } else {
6826
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
6827
            // if the course was unset and the session was set, send directly to the session
6828
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6829
        }
6830
    }
6831
6832
    // if not valid combination was found, return an empty string
6833
    return $url;
6834
}
6835
6836
/**
6837
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6838
 *
6839
 * @return bool true if multi site is enabled
6840
 */
6841
function api_get_multiple_access_url()
6842
{
6843
    global $_configuration;
6844
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6845
        return true;
6846
    }
6847
6848
    return false;
6849
}
6850
6851
/**
6852
 * @return bool
6853
 */
6854
function api_is_multiple_url_enabled()
6855
{
6856
    return api_get_multiple_access_url();
6857
}
6858
6859
/**
6860
 * Returns a md5 unique id.
6861
 *
6862
 * @todo add more parameters
6863
 */
6864
function api_get_unique_id()
6865
{
6866
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6867
6868
    return $id;
6869
}
6870
6871
/**
6872
 * @param int Course id
6873
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6874
 * @param int the item id (tool id, exercise id, lp id)
6875
 *
6876
 * @return bool
6877
 */
6878
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6879
{
6880
    if (api_is_platform_admin()) {
6881
        return false;
6882
    }
6883
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
6884
        if (empty($course_code)) {
6885
            $course_code = api_get_course_id();
6886
        }
6887
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6888
        $item_id = (int) $item_id;
6889
        $link_type = (int) $link_type;
6890
        $course_code = Database::escape_string($course_code);
6891
        $sql = "SELECT locked FROM $table
6892
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6893
        $result = Database::query($sql);
6894
        if (Database::num_rows($result)) {
6895
            return true;
6896
        }
6897
    }
6898
6899
    return false;
6900
}
6901
6902
/**
6903
 * Blocks a page if the item was added in a gradebook.
6904
 *
6905
 * @param int       exercise id, work id, thread id,
6906
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6907
 * see gradebook/lib/be/linkfactory
6908
 * @param string    course code
6909
 *
6910
 * @return false|null
6911
 */
6912
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6913
{
6914
    if (api_is_platform_admin()) {
6915
        return false;
6916
    }
6917
6918
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6919
        $message = Display::return_message(get_lang('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.'), 'warning');
6920
        api_not_allowed(true, $message);
6921
    }
6922
}
6923
6924
/**
6925
 * Checks the PHP version installed is enough to run Chamilo.
6926
 *
6927
 * @param string Include path (used to load the error page)
6928
 */
6929
function api_check_php_version()
6930
{
6931
    if (!function_exists('version_compare') ||
6932
        version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')
6933
    ) {
6934
        throw new Exception('Wrong PHP version');
6935
    }
6936
}
6937
6938
/**
6939
 * Checks whether the Archive directory is present and writeable. If not,
6940
 * prints a warning message.
6941
 */
6942
function api_check_archive_dir()
6943
{
6944
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6945
        $message = Display::return_message(get_lang('The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'), 'warning');
6946
        api_not_allowed(true, $message);
6947
    }
6948
}
6949
6950
/**
6951
 * Returns an array of global configuration settings which should be ignored
6952
 * when printing the configuration settings screens.
6953
 *
6954
 * @return array Array of strings, each identifying one of the excluded settings
6955
 */
6956
function api_get_locked_settings()
6957
{
6958
    return [
6959
        'permanently_remove_deleted_files',
6960
        'account_valid_duration',
6961
        'service_ppt2lp',
6962
        'wcag_anysurfer_public_pages',
6963
        'upload_extensions_list_type',
6964
        'upload_extensions_blacklist',
6965
        'upload_extensions_whitelist',
6966
        'upload_extensions_skip',
6967
        'upload_extensions_replace_by',
6968
        'hide_dltt_markup',
6969
        'split_users_upload_directory',
6970
        'permissions_for_new_directories',
6971
        'permissions_for_new_files',
6972
        'platform_charset',
6973
        'ldap_description',
6974
        'cas_activate',
6975
        'cas_server',
6976
        'cas_server_uri',
6977
        'cas_port',
6978
        'cas_protocol',
6979
        'cas_add_user_activate',
6980
        'update_user_info_cas_with_ldap',
6981
        'languagePriority1',
6982
        'languagePriority2',
6983
        'languagePriority3',
6984
        'languagePriority4',
6985
        'login_is_email',
6986
        'chamilo_database_version',
6987
    ];
6988
}
6989
6990
/**
6991
 * Guess the real ip for register in the database, even in reverse proxy cases.
6992
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6993
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6994
 * Note: the result of this function is not SQL-safe. Please escape it before
6995
 * inserting in a database.
6996
 *
6997
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6998
 *
6999
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7000
 *
7001
 * @version CEV CHANGE 24APR2012
7002
 */
7003
function api_get_real_ip()
7004
{
7005
    $ip = trim($_SERVER['REMOTE_ADDR']);
7006
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7007
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7008
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7009
        } else {
7010
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7011
        }
7012
        $ip = trim($ip1);
7013
    }
7014
7015
    return $ip;
7016
}
7017
7018
/**
7019
 * Checks whether an IP is included inside an IP range.
7020
 *
7021
 * @param string IP address
7022
 * @param string IP range
7023
 * @param string $ip
7024
 *
7025
 * @return bool True if IP is in the range, false otherwise
7026
 *
7027
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7028
 * @author Yannick Warnier for improvements and managment of multiple ranges
7029
 *
7030
 * @todo check for IPv6 support
7031
 */
7032
function api_check_ip_in_range($ip, $range)
7033
{
7034
    if (empty($ip) or empty($range)) {
7035
        return false;
7036
    }
7037
    $ip_ip = ip2long($ip);
7038
    // divide range param into array of elements
7039
    if (false !== strpos($range, ',')) {
7040
        $ranges = explode(',', $range);
7041
    } else {
7042
        $ranges = [$range];
7043
    }
7044
    foreach ($ranges as $range) {
0 ignored issues
show
$range is overwriting one of the parameters of this function.
Loading history...
7045
        $range = trim($range);
7046
        if (empty($range)) {
7047
            continue;
7048
        }
7049
        if (false === strpos($range, '/')) {
7050
            if (0 === strcmp($ip, $range)) {
7051
                return true; // there is a direct IP match, return OK
7052
            }
7053
            continue; //otherwise, get to the next range
7054
        }
7055
        // the range contains a "/", so analyse completely
7056
        [$net, $mask] = explode("/", $range);
7057
7058
        $ip_net = ip2long($net);
7059
        // mask binary magic
7060
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7061
7062
        $ip_ip_net = $ip_ip & $ip_mask;
7063
        if ($ip_ip_net == $ip_net) {
7064
            return true;
7065
        }
7066
    }
7067
7068
    return false;
7069
}
7070
7071
function api_check_user_access_to_legal($course_visibility)
7072
{
7073
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7074
7075
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7076
}
7077
7078
/**
7079
 * Checks if the global chat is enabled or not.
7080
 *
7081
 * @return bool
7082
 */
7083
function api_is_global_chat_enabled()
7084
{
7085
    return
7086
        !api_is_anonymous() &&
7087
        'true' === api_get_setting('allow_global_chat') &&
7088
        'true' === api_get_setting('allow_social_tool');
7089
}
7090
7091
/**
7092
 * @param int   $item_id
7093
 * @param int   $tool_id
7094
 * @param int   $group_id   id
7095
 * @param array $courseInfo
7096
 * @param int   $sessionId
7097
 * @param int   $userId
7098
 *
7099
 * @deprecated
7100
 */
7101
function api_set_default_visibility(
7102
    $item_id,
7103
    $tool_id,
7104
    $group_id = 0,
7105
    $courseInfo = [],
7106
    $sessionId = 0,
7107
    $userId = 0
7108
) {
7109
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7110
    $courseId = $courseInfo['real_id'];
7111
    $courseCode = $courseInfo['code'];
7112
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7113
    $userId = empty($userId) ? api_get_user_id() : $userId;
7114
7115
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7116
    if (is_null($group_id)) {
7117
        $group_id = 0;
7118
    } else {
7119
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7120
    }
7121
7122
    $groupInfo = [];
7123
    if (!empty($group_id)) {
7124
        $groupInfo = GroupManager::get_group_properties($group_id);
7125
    }
7126
    $original_tool_id = $tool_id;
7127
7128
    switch ($tool_id) {
7129
        case TOOL_LINK:
7130
        case TOOL_LINK_CATEGORY:
7131
            $tool_id = 'links';
7132
            break;
7133
        case TOOL_DOCUMENT:
7134
            $tool_id = 'documents';
7135
            break;
7136
        case TOOL_LEARNPATH:
7137
            $tool_id = 'learning';
7138
            break;
7139
        case TOOL_ANNOUNCEMENT:
7140
            $tool_id = 'announcements';
7141
            break;
7142
        case TOOL_FORUM:
7143
        case TOOL_FORUM_CATEGORY:
7144
        case TOOL_FORUM_THREAD:
7145
            $tool_id = 'forums';
7146
            break;
7147
        case TOOL_QUIZ:
7148
            $tool_id = 'quiz';
7149
            break;
7150
    }
7151
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7152
7153
    if (isset($setting[$tool_id])) {
7154
        $visibility = 'invisible';
7155
        if ('true' == $setting[$tool_id]) {
7156
            $visibility = 'visible';
7157
        }
7158
7159
        // Read the portal and course default visibility
7160
        if ('documents' === $tool_id) {
7161
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
7162
        }
7163
7164
        /*api_item_property_update(
7165
            $courseInfo,
7166
            $original_tool_id,
7167
            $item_id,
7168
            $visibility,
7169
            $userId,
7170
            $groupInfo,
7171
            null,
7172
            null,
7173
            null,
7174
            $sessionId
7175
        );*/
7176
7177
        // Fixes default visibility for tests
7178
        switch ($original_tool_id) {
7179
            case TOOL_QUIZ:
7180
                if (empty($sessionId)) {
7181
                    $objExerciseTmp = new Exercise($courseId);
7182
                    $objExerciseTmp->read($item_id);
7183
                    if ('visible' == $visibility) {
7184
                        $objExerciseTmp->enable();
7185
                        $objExerciseTmp->save();
7186
                    } else {
7187
                        $objExerciseTmp->disable();
7188
                        $objExerciseTmp->save();
7189
                    }
7190
                }
7191
                break;
7192
        }
7193
    }
7194
}
7195
7196
/**
7197
 * @return string
7198
 */
7199
function api_get_security_key()
7200
{
7201
    return api_get_configuration_value('security_key');
7202
}
7203
7204
/**
7205
 * @param int $user_id
7206
 * @param int $courseId
7207
 * @param int $session_id
7208
 *
7209
 * @return array
7210
 */
7211
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7212
{
7213
    $user_roles = [];
7214
    $courseInfo = api_get_course_info_by_id($courseId);
7215
    $course_code = $courseInfo['code'];
7216
7217
    $url_id = api_get_current_access_url_id();
7218
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7219
        $user_roles[] = PLATFORM_ADMIN;
7220
    }
7221
7222
    /*if (api_is_drh()) {
7223
        $user_roles[] = DRH;
7224
    }*/
7225
7226
    if (!empty($session_id)) {
7227
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7228
            $user_roles[] = SESSION_GENERAL_COACH;
7229
        }
7230
    }
7231
7232
    if (!empty($course_code)) {
7233
        if (empty($session_id)) {
7234
            if (CourseManager::isCourseTeacher($user_id, $courseInfo['real_id'])) {
7235
                $user_roles[] = COURSEMANAGER;
7236
            }
7237
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7238
                $user_roles[] = COURSE_TUTOR;
7239
            }
7240
7241
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7242
                $user_roles[] = COURSE_STUDENT;
7243
            }
7244
        } else {
7245
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7246
                $user_id,
7247
                $courseId,
7248
                $session_id
7249
            );
7250
7251
            if (!empty($user_status_in_session)) {
7252
                if (0 == $user_status_in_session) {
7253
                    $user_roles[] = SESSION_STUDENT;
7254
                }
7255
                if (2 == $user_status_in_session) {
7256
                    $user_roles[] = SESSION_COURSE_COACH;
7257
                }
7258
            }
7259
7260
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7261
               $user_roles[] = SESSION_COURSE_COACH;
7262
            }*/
7263
        }
7264
    }
7265
7266
    return $user_roles;
7267
}
7268
7269
/**
7270
 * @param int $courseId
7271
 * @param int $session_id
7272
 *
7273
 * @return bool
7274
 */
7275
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7276
{
7277
    if (api_is_platform_admin()) {
7278
        return true;
7279
    }
7280
7281
    $user_id = api_get_user_id();
7282
7283
    if (empty($courseId)) {
7284
        $courseId = api_get_course_int_id();
7285
    }
7286
7287
    if (empty($session_id)) {
7288
        $session_id = api_get_session_id();
7289
    }
7290
7291
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7292
7293
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7294
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7295
        return true;
7296
    } else {
7297
        if (in_array(COURSEMANAGER, $roles)) {
7298
            return true;
7299
        }
7300
7301
        return false;
7302
    }
7303
}
7304
7305
/**
7306
 * @param string $file
7307
 *
7308
 * @return string
7309
 */
7310
function api_get_js_simple($file)
7311
{
7312
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7313
}
7314
7315
/**
7316
 * Modify default memory_limit and max_execution_time limits
7317
 * Needed when processing long tasks.
7318
 */
7319
function api_set_more_memory_and_time_limits()
7320
{
7321
    if (function_exists('ini_set')) {
7322
        api_set_memory_limit('256M');
7323
        ini_set('max_execution_time', 1800);
7324
    }
7325
}
7326
7327
/**
7328
 * Tries to set memory limit, if authorized and new limit is higher than current.
7329
 *
7330
 * @param string $mem New memory limit
7331
 *
7332
 * @return bool True on success, false on failure or current is higher than suggested
7333
 * @assert (null) === false
7334
 * @assert (-1) === false
7335
 * @assert (0) === true
7336
 * @assert ('1G') === true
7337
 */
7338
function api_set_memory_limit($mem)
7339
{
7340
    //if ini_set() not available, this function is useless
7341
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
7342
        return false;
7343
    }
7344
7345
    $memory_limit = ini_get('memory_limit');
7346
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7347
        ini_set('memory_limit', $mem);
7348
7349
        return true;
7350
    }
7351
7352
    return false;
7353
}
7354
7355
/**
7356
 * Gets memory limit in bytes.
7357
 *
7358
 * @param string The memory size (128M, 1G, 1000K, etc)
7359
 *
7360
 * @return int
7361
 * @assert (null) === false
7362
 * @assert ('1t')  === 1099511627776
7363
 * @assert ('1g')  === 1073741824
7364
 * @assert ('1m')  === 1048576
7365
 * @assert ('100k') === 102400
7366
 */
7367
function api_get_bytes_memory_limit($mem)
7368
{
7369
    $size = strtolower(substr($mem, -1));
7370
7371
    switch ($size) {
7372
        case 't':
7373
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7374
            break;
7375
        case 'g':
7376
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7377
            break;
7378
        case 'm':
7379
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7380
            break;
7381
        case 'k':
7382
            $mem = intval(substr($mem, 0, -1)) * 1024;
7383
            break;
7384
        default:
7385
            // we assume it's integer only
7386
            $mem = intval($mem);
7387
            break;
7388
    }
7389
7390
    return $mem;
7391
}
7392
7393
/**
7394
 * Finds all the information about a user from username instead of user id.
7395
 *
7396
 * @param string $officialCode
7397
 *
7398
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7399
 *
7400
 * @author Yannick Warnier <[email protected]>
7401
 */
7402
function api_get_user_info_from_official_code($officialCode)
7403
{
7404
    if (empty($officialCode)) {
7405
        return false;
7406
    }
7407
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7408
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7409
    $result = Database::query($sql);
7410
    if (Database::num_rows($result) > 0) {
7411
        $result_array = Database::fetch_array($result);
7412
7413
        return _api_format_user($result_array);
7414
    }
7415
7416
    return false;
7417
}
7418
7419
/**
7420
 * @param string $usernameInputId
7421
 * @param string $passwordInputId
7422
 *
7423
 * @return string|null
7424
 */
7425
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7426
{
7427
    $checkPass = api_get_setting('allow_strength_pass_checker');
7428
    $useStrengthPassChecker = 'true' === $checkPass;
7429
7430
    if (false === $useStrengthPassChecker) {
7431
        return null;
7432
    }
7433
7434
    $translations = [
7435
        'wordLength' => get_lang('The password is too short'),
7436
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7437
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7438
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7439
        'wordRepetitions' => get_lang('Too many repetitions'),
7440
        'wordSequences' => get_lang('Your password contains sequences'),
7441
        'errorList' => get_lang('errors found'),
7442
        'veryWeak' => get_lang('Very weak'),
7443
        'weak' => get_lang('Weak'),
7444
        'normal' => get_lang('Normal'),
7445
        'medium' => get_lang('Medium'),
7446
        'strong' => get_lang('Strong'),
7447
        'veryStrong' => get_lang('Very strong'),
7448
    ];
7449
7450
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.js');
7451
    $js .= "<script>
7452
    var errorMessages = {
7453
        password_to_short : \"".get_lang('The password is too short')."\",
7454
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7455
    };
7456
7457
    $(function() {
7458
        var lang = ".json_encode($translations).";
7459
        var options = {
7460
            onLoad : function () {
7461
                //$('#messages').text('Start typing password');
7462
            },
7463
            onKeyUp: function (evt) {
7464
                $(evt.target).pwstrength('outputErrorList');
7465
            },
7466
            errorMessages : errorMessages,
7467
            viewports: {
7468
                progress: '#password_progress',
7469
                verdict: '#password-verdict',
7470
                errors: '#password-errors'
7471
            },
7472
            usernameField: '$usernameInputId'
7473
        };
7474
        options.i18n = {
7475
            t: function (key) {
7476
                var result = lang[key];
7477
                return result === key ? '' : result; // This assumes you return the
7478
            }
7479
        };
7480
        $('".$passwordInputId."').pwstrength(options);
7481
    });
7482
    </script>";
7483
7484
    return $js;
7485
}
7486
7487
/**
7488
 * create an user extra field called 'captcha_blocked_until_date'.
7489
 *
7490
 * @param string $username
7491
 *
7492
 * @return bool
7493
 */
7494
function api_block_account_captcha($username)
7495
{
7496
    $userInfo = api_get_user_info_from_username($username);
7497
    if (empty($userInfo)) {
7498
        return false;
7499
    }
7500
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7501
    $time = time() + $minutesToBlock * 60;
7502
    UserManager::update_extra_field_value(
7503
        $userInfo['user_id'],
7504
        'captcha_blocked_until_date',
7505
        api_get_utc_datetime($time)
7506
    );
7507
7508
    return true;
7509
}
7510
7511
/**
7512
 * @param string $username
7513
 *
7514
 * @return bool
7515
 */
7516
function api_clean_account_captcha($username)
7517
{
7518
    $userInfo = api_get_user_info_from_username($username);
7519
    if (empty($userInfo)) {
7520
        return false;
7521
    }
7522
    Session::erase('loginFailedCount');
7523
    UserManager::update_extra_field_value(
7524
        $userInfo['user_id'],
7525
        'captcha_blocked_until_date',
7526
        null
7527
    );
7528
7529
    return true;
7530
}
7531
7532
/**
7533
 * @param string $username
7534
 *
7535
 * @return bool
7536
 */
7537
function api_get_user_blocked_by_captcha($username)
7538
{
7539
    $userInfo = api_get_user_info_from_username($username);
7540
    if (empty($userInfo)) {
7541
        return false;
7542
    }
7543
    $data = UserManager::get_extra_user_data_by_field(
7544
        $userInfo['user_id'],
7545
        'captcha_blocked_until_date'
7546
    );
7547
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7548
        return $data['captcha_blocked_until_date'];
7549
    }
7550
7551
    return false;
7552
}
7553
7554
/**
7555
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7556
 * Postfix the text with "..." if it has been truncated.
7557
 *
7558
 * @param string $text
7559
 * @param int    $number
7560
 *
7561
 * @return string
7562
 *
7563
 * @author hubert borderiou
7564
 */
7565
function api_get_short_text_from_html($text, $number)
7566
{
7567
    // Delete script and style tags
7568
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7569
    $text = api_html_entity_decode($text);
7570
    $out_res = api_remove_tags_with_space($text, false);
7571
    $postfix = "...";
7572
    if (strlen($out_res) > $number) {
7573
        $out_res = substr($out_res, 0, $number).$postfix;
7574
    }
7575
7576
    return $out_res;
7577
}
7578
7579
/**
7580
 * Replace tags with a space in a text.
7581
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7582
 *
7583
 * @return string
7584
 *
7585
 * @author hubert borderiou
7586
 */
7587
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7588
{
7589
    $out_res = $in_html;
7590
    if ($in_double_quote_replace) {
7591
        $out_res = str_replace('"', "''", $out_res);
7592
    }
7593
    // avoid text stuck together when tags are removed, adding a space after >
7594
    $out_res = str_replace(">", "> ", $out_res);
7595
    $out_res = strip_tags($out_res);
7596
7597
    return $out_res;
7598
}
7599
7600
/**
7601
 * If true, the drh can access all content (courses, users) inside a session.
7602
 *
7603
 * @return bool
7604
 */
7605
function api_drh_can_access_all_session_content()
7606
{
7607
    return 'true' === api_get_setting('drh_can_access_all_session_content');
7608
}
7609
7610
/**
7611
 * @param string $tool
7612
 * @param string $setting
7613
 * @param int    $defaultValue
7614
 *
7615
 * @return string
7616
 */
7617
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7618
{
7619
    global $_configuration;
7620
    if (isset($_configuration[$tool]) &&
7621
        isset($_configuration[$tool]['default_settings']) &&
7622
        isset($_configuration[$tool]['default_settings'][$setting])
7623
    ) {
7624
        return $_configuration[$tool]['default_settings'][$setting];
7625
    }
7626
7627
    return $defaultValue;
7628
}
7629
7630
/**
7631
 * Checks if user can login as another user.
7632
 *
7633
 * @param int $loginAsUserId the user id to log in
7634
 * @param int $userId        my user id
7635
 *
7636
 * @return bool
7637
 */
7638
function api_can_login_as($loginAsUserId, $userId = null)
7639
{
7640
    $loginAsUserId = (int) $loginAsUserId;
7641
7642
    if (empty($loginAsUserId)) {
7643
        return false;
7644
    }
7645
7646
    if (empty($userId)) {
7647
        $userId = api_get_user_id();
7648
    }
7649
7650
    if ($loginAsUserId == $userId) {
7651
        return false;
7652
    }
7653
7654
    // Check if the user to login is an admin
7655
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7656
        // Only super admins can login to admin accounts
7657
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7658
            return false;
7659
        }
7660
    }
7661
7662
    $userInfo = api_get_user_info($loginAsUserId);
7663
    $isDrh = function () use ($loginAsUserId) {
7664
        if (api_is_drh()) {
7665
            if (api_drh_can_access_all_session_content()) {
7666
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7667
                    'drh_all',
7668
                    api_get_user_id()
7669
                );
7670
                $userList = [];
7671
                if (is_array($users)) {
7672
                    foreach ($users as $user) {
7673
                        $userList[] = $user['id'];
7674
                    }
7675
                }
7676
                if (in_array($loginAsUserId, $userList)) {
7677
                    return true;
7678
                }
7679
            } else {
7680
                if (api_is_drh() &&
7681
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7682
                ) {
7683
                    return true;
7684
                }
7685
            }
7686
        }
7687
7688
        return false;
7689
    };
7690
7691
    $loginAsStatusForSessionAdmins = [STUDENT];
7692
7693
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
7694
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
7695
    }
7696
7697
    return api_is_platform_admin() ||
7698
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
7699
        $isDrh();
7700
}
7701
7702
/**
7703
 * @return bool
7704
 */
7705
function api_is_allowed_in_course()
7706
{
7707
    if (api_is_platform_admin()) {
7708
        return true;
7709
    }
7710
7711
    $user = api_get_current_user();
7712
    if ($user instanceof User) {
7713
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
7714
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
7715
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
7716
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
7717
        ) {
7718
            return true;
7719
        }
7720
    }
7721
7722
    return false;
7723
}
7724
7725
/**
7726
 * Return true on https install.
7727
 *
7728
 * @return bool
7729
 */
7730
function api_is_https()
7731
{
7732
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
7733
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
7734
    ) {
7735
        $isSecured = true;
7736
    } else {
7737
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
7738
            $isSecured = true;
7739
        } else {
7740
            $isSecured = false;
7741
            // last chance
7742
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
7743
                $isSecured = true;
7744
            }
7745
        }
7746
    }
7747
7748
    return $isSecured;
7749
}
7750
7751
/**
7752
 * Return protocol (http or https).
7753
 *
7754
 * @return string
7755
 */
7756
function api_get_protocol()
7757
{
7758
    return api_is_https() ? 'https' : 'http';
7759
}
7760
7761
/**
7762
 * Return a string where " are replaced with 2 '
7763
 * It is useful when you pass a PHP variable in a Javascript browser dialog
7764
 * e.g. : alert("<?php get_lang('Message') ?>");
7765
 * and message contains character ".
7766
 *
7767
 * @param string $in_text
7768
 *
7769
 * @return string
7770
 */
7771
function convert_double_quote_to_single($in_text)
7772
{
7773
    return api_preg_replace('/"/', "''", $in_text);
7774
}
7775
7776
/**
7777
 * Get origin.
7778
 *
7779
 * @param string
7780
 *
7781
 * @return string
7782
 */
7783
function api_get_origin()
7784
{
7785
    return isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7786
}
7787
7788
/**
7789
 * Warns an user that the portal reach certain limit.
7790
 *
7791
 * @param string $limitName
7792
 */
7793
function api_warn_hosting_contact($limitName)
7794
{
7795
    $hostingParams = api_get_configuration_value(1);
7796
    $email = null;
7797
7798
    if (!empty($hostingParams)) {
7799
        if (isset($hostingParams['hosting_contact_mail'])) {
7800
            $email = $hostingParams['hosting_contact_mail'];
7801
        }
7802
    }
7803
7804
    if (!empty($email)) {
7805
        $subject = get_lang('Hosting warning reached');
7806
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
7807
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
7808
        if (isset($hostingParams[$limitName])) {
7809
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7810
        }
7811
        api_mail_html(null, $email, $subject, $body);
7812
    }
7813
}
7814
7815
/**
7816
 * Gets value of a variable from config/configuration.php
7817
 * Variables that are not set in the configuration.php file but set elsewhere:
7818
 * - virtual_css_theme_folder (vchamilo plugin)
7819
 * - access_url (global.inc.php)
7820
 * - apc/apc_prefix (global.inc.php).
7821
 *
7822
 * @param string $variable
7823
 *
7824
 * @return bool|mixed
7825
 */
7826
function api_get_configuration_value($variable)
7827
{
7828
    global $_configuration;
7829
    // Check the current url id, id = 1 by default
7830
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7831
7832
    $variable = trim($variable);
7833
7834
    // Check if variable exists
7835
    if (isset($_configuration[$variable])) {
7836
        if (is_array($_configuration[$variable])) {
7837
            // Check if it exists for the sub portal
7838
            if (array_key_exists($urlId, $_configuration[$variable])) {
7839
                return $_configuration[$variable][$urlId];
7840
            } else {
7841
                // Try to found element with id = 1 (master portal)
7842
                if (array_key_exists(1, $_configuration[$variable])) {
7843
                    return $_configuration[$variable][1];
7844
                }
7845
            }
7846
        }
7847
7848
        return $_configuration[$variable];
7849
    }
7850
7851
    return false;
7852
}
7853
7854
/**
7855
 * Retreives and returns a value in a hierarchical configuration array
7856
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
7857
 *
7858
 * @param string $path      the successive array keys, separated by the separator
7859
 * @param mixed  $default   value to be returned if not found, null by default
7860
 * @param string $separator '/' by default
7861
 * @param array  $array     the active configuration array by default
7862
 *
7863
 * @return mixed the found value or $default
7864
 */
7865
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
7866
{
7867
    $pos = strpos($path, $separator);
7868
    if (false === $pos) {
7869
        if (is_null($array)) {
7870
            return api_get_configuration_value($path);
7871
        }
7872
        if (is_array($array) && array_key_exists($path, $array)) {
7873
            return $array[$path];
7874
        }
7875
7876
        return $default;
7877
    }
7878
    $key = substr($path, 0, $pos);
7879
    if (is_null($array)) {
7880
        $newArray = api_get_configuration_value($key);
7881
    } elseif (is_array($array) && array_key_exists($key, $array)) {
7882
        $newArray = $array[$key];
7883
    } else {
7884
        return $default;
7885
    }
7886
    if (is_array($newArray)) {
7887
        $newPath = substr($path, $pos + 1);
7888
7889
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
7890
    }
7891
7892
    return $default;
7893
}
7894
7895
/**
7896
 * Retrieves and returns a value in a hierarchical configuration array
7897
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
7898
 *
7899
 * @param array  $array     the recursive array that contains the value to be returned (or not)
7900
 * @param string $path      the successive array keys, separated by the separator
7901
 * @param mixed  $default   the value to be returned if not found
7902
 * @param string $separator the separator substring
7903
 *
7904
 * @return mixed the found value or $default
7905
 */
7906
function api_array_sub_value($array, $path, $default = null, $separator = '/')
7907
{
7908
    $pos = strpos($path, $separator);
7909
    if (false === $pos) {
7910
        if (is_array($array) && array_key_exists($path, $array)) {
7911
            return $array[$path];
7912
        }
7913
7914
        return $default;
7915
    }
7916
    $key = substr($path, 0, $pos);
7917
    if (is_array($array) && array_key_exists($key, $array)) {
7918
        $newArray = $array[$key];
7919
    } else {
7920
        return $default;
7921
    }
7922
    if (is_array($newArray)) {
7923
        $newPath = substr($path, $pos + 1);
7924
7925
        return api_array_sub_value($newArray, $newPath, $default);
7926
    }
7927
7928
    return $default;
7929
}
7930
7931
/**
7932
 * Returns supported image extensions in the portal.
7933
 *
7934
 * @param bool $supportVectors Whether vector images should also be accepted or not
7935
 *
7936
 * @return array Supported image extensions in the portal
7937
 */
7938
function api_get_supported_image_extensions($supportVectors = true)
7939
{
7940
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
7941
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
7942
    if ($supportVectors) {
7943
        array_push($supportedImageExtensions, 'svg');
7944
    }
7945
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
7946
        array_push($supportedImageExtensions, 'webp');
7947
    }
7948
7949
    return $supportedImageExtensions;
7950
}
7951
7952
/**
7953
 * This setting changes the registration status for the campus.
7954
 *
7955
 * @author Patrick Cool <[email protected]>, Ghent University
7956
 *
7957
 * @version August 2006
7958
 *
7959
 * @param bool $listCampus Whether we authorize
7960
 *
7961
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
7962
 */
7963
function api_register_campus($listCampus = true)
7964
{
7965
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
7966
7967
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
7968
    Database::query($sql);
7969
7970
    if (!$listCampus) {
7971
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
7972
        Database::query($sql);
7973
    }
7974
}
7975
7976
/**
7977
 * Checks whether current user is a student boss.
7978
 *
7979
 * @global array $_user
7980
 *
7981
 * @return bool
7982
 */
7983
function api_is_student_boss()
7984
{
7985
    $_user = api_get_user_info();
7986
7987
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
7988
}
7989
7990
/**
7991
 * Check whether the user type should be exclude.
7992
 * Such as invited or anonymous users.
7993
 *
7994
 * @param bool $checkDB Optional. Whether check the user status
7995
 * @param int  $userId  Options. The user id
7996
 *
7997
 * @return bool
7998
 */
7999
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8000
{
8001
    if ($checkDB) {
8002
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8003
8004
        if (0 == $userId) {
8005
            return true;
8006
        }
8007
8008
        $userInfo = api_get_user_info($userId);
8009
8010
        switch ($userInfo['status']) {
8011
            case INVITEE:
8012
            case ANONYMOUS:
8013
                return true;
8014
            default:
8015
                return false;
8016
        }
8017
    }
8018
8019
    $isInvited = api_is_invitee();
8020
    $isAnonymous = api_is_anonymous();
8021
8022
    if ($isInvited || $isAnonymous) {
8023
        return true;
8024
    }
8025
8026
    return false;
8027
}
8028
8029
/**
8030
 * Get the user status to ignore in reports.
8031
 *
8032
 * @param string $format Optional. The result type (array or string)
8033
 *
8034
 * @return array|string
8035
 */
8036
function api_get_users_status_ignored_in_reports($format = 'array')
8037
{
8038
    $excludedTypes = [
8039
        INVITEE,
8040
        ANONYMOUS,
8041
    ];
8042
8043
    if ('string' == $format) {
8044
        return implode(', ', $excludedTypes);
8045
    }
8046
8047
    return $excludedTypes;
8048
}
8049
8050
/**
8051
 * Set the Site Use Cookie Warning for 1 year.
8052
 */
8053
function api_set_site_use_cookie_warning_cookie()
8054
{
8055
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8056
}
8057
8058
/**
8059
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8060
 *
8061
 * @return bool
8062
 */
8063
function api_site_use_cookie_warning_cookie_exist()
8064
{
8065
    return isset($_COOKIE['ChamiloUsesCookies']);
8066
}
8067
8068
/**
8069
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8070
 *
8071
 * @param int    $time         The time in seconds
8072
 * @param string $originFormat Optional. PHP o JS
8073
 *
8074
 * @return string (00h00'00")
8075
 */
8076
function api_format_time($time, $originFormat = 'php')
8077
{
8078
    $h = get_lang('h');
8079
    $hours = $time / 3600;
8080
    $mins = ($time % 3600) / 60;
8081
    $secs = ($time % 60);
8082
8083
    if ($time < 0) {
8084
        $hours = 0;
8085
        $mins = 0;
8086
        $secs = 0;
8087
    }
8088
8089
    if ('js' == $originFormat) {
8090
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8091
    } else {
8092
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8093
    }
8094
8095
    return $formattedTime;
8096
}
8097
8098
/**
8099
 * Create a new empty directory with index.html file.
8100
 *
8101
 * @param string $name            The new directory name
8102
 * @param string $parentDirectory Directory parent directory name
8103
 *
8104
 * @deprecated use Resources
8105
 *
8106
 * @return bool Return true if the directory was create. Otherwise return false
8107
 */
8108
function api_create_protected_dir($name, $parentDirectory)
8109
{
8110
    $isCreated = false;
8111
8112
    if (!is_writable($parentDirectory)) {
8113
        return false;
8114
    }
8115
8116
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8117
8118
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8119
        $fp = fopen($fullPath.'/index.html', 'w');
8120
8121
        if ($fp) {
8122
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8123
                $isCreated = true;
8124
            }
8125
        }
8126
8127
        fclose($fp);
8128
    }
8129
8130
    return $isCreated;
8131
}
8132
8133
/**
8134
 * Sends an email
8135
 * Sender name and email can be specified, if not specified
8136
 * name and email of the platform admin are used.
8137
 *
8138
 * @param string    name of recipient
8139
 * @param string    email of recipient
8140
 * @param string    email subject
8141
 * @param string    email body
8142
 * @param string    sender name
8143
 * @param string    sender e-mail
8144
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8145
 * @param array     data file (path and filename)
8146
 * @param bool      True for attaching a embedded file inside content html (optional)
8147
 * @param array     Additional parameters
8148
 *
8149
 * @return bool true if mail was sent
8150
 */
8151
function api_mail_html(
8152
    $recipientName,
8153
    $recipientEmail,
8154
    $subject,
8155
    $body,
8156
    $senderName = '',
8157
    $senderEmail = '',
8158
    $extra_headers = [],
8159
    $data_file = [],
8160
    $embeddedImage = false,
8161
    $additionalParameters = []
8162
) {
8163
    if (!api_valid_email($recipientEmail)) {
8164
        return false;
8165
    }
8166
8167
    // Default values
8168
    $notification = new Notification();
8169
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8170
    $defaultName = $notification->getDefaultPlatformSenderName();
8171
8172
    // If the parameter is set don't use the admin.
8173
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8174
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8175
8176
    // Reply to first
8177
    $replyToName = '';
8178
    $replyToEmail = '';
8179
    if (isset($extra_headers['reply_to'])) {
8180
        $replyToEmail = $extra_headers['reply_to']['mail'];
8181
        $replyToName = $extra_headers['reply_to']['name'];
8182
    }
8183
8184
    try {
8185
        $message = new TemplatedEmail();
8186
        $message->subject($subject);
8187
8188
        $list = api_get_configuration_value('send_all_emails_to');
8189
        if (!empty($list) && isset($list['emails'])) {
8190
            foreach ($list['emails'] as $email) {
8191
                $message->cc($email);
8192
            }
8193
        }
8194
8195
        // Attachment
8196
        if (!empty($data_file)) {
8197
            foreach ($data_file as $file_attach) {
8198
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8199
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
8200
                }
8201
            }
8202
        }
8203
8204
        $noReply = api_get_setting('noreply_email_address');
8205
        $automaticEmailText = '';
8206
        if (!empty($noReply)) {
8207
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
8208
        }
8209
8210
        $params = [
8211
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8212
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8213
            'link' => $additionalParameters['link'] ?? '',
8214
            'automatic_email_text' => $automaticEmailText,
8215
            'content' => $body,
8216
            'theme' => api_get_visual_theme(),
8217
        ];
8218
8219
        if (!empty($senderEmail)) {
8220
            $message->from(new Address($senderEmail, $senderName));
8221
        }
8222
8223
        if (!empty($recipientEmail)) {
8224
            $message->to(new Address($recipientEmail, $recipientName));
8225
        }
8226
8227
        if (!empty($replyToEmail)) {
8228
            $message->replyTo(new Address($replyToEmail, $replyToName));
8229
        }
8230
8231
        $message
8232
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
8233
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
8234
        ;
8235
        $message->context($params);
8236
        Container::getMailer()->send($message);
8237
8238
        return true;
8239
    } catch (Exception $e) {
8240
        error_log($e->getMessage());
8241
    }
8242
8243
    if (!empty($additionalParameters)) {
8244
        $plugin = new AppPlugin();
8245
        $smsPlugin = $plugin->getSMSPluginLibrary();
8246
        if ($smsPlugin) {
8247
            $smsPlugin->send($additionalParameters);
8248
        }
8249
    }
8250
8251
    return 1;
8252
}
8253
8254
/**
8255
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8256
 * @param bool   $showHeader
8257
 */
8258
function api_protect_course_group($tool, $showHeader = true)
8259
{
8260
    $groupId = api_get_group_id();
8261
    if (!empty($groupId)) {
8262
        if (api_is_platform_admin()) {
8263
            return true;
8264
        }
8265
8266
        if (api_is_allowed_to_edit(false, true, true)) {
8267
            return true;
8268
        }
8269
8270
        $userId = api_get_user_id();
8271
        $sessionId = api_get_session_id();
8272
        if (!empty($sessionId)) {
8273
            if (api_is_coach($sessionId, api_get_course_int_id())) {
8274
                return true;
8275
            }
8276
8277
            if (api_is_drh()) {
8278
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
8279
                    return true;
8280
                }
8281
            }
8282
        }
8283
8284
        $groupInfo = GroupManager::get_group_properties($groupId);
8285
8286
        // Group doesn't exists
8287
        if (empty($groupInfo)) {
8288
            api_not_allowed($showHeader);
8289
        }
8290
8291
        // Check group access
8292
        $allow = GroupManager::user_has_access(
8293
            $userId,
8294
            $groupInfo['iid'],
8295
            $tool
8296
        );
8297
8298
        if (!$allow) {
8299
            api_not_allowed($showHeader);
8300
        }
8301
    }
8302
8303
    return false;
8304
}
8305
8306
/**
8307
 * Check if a date is in a date range.
8308
 *
8309
 * @param datetime $startDate
8310
 * @param datetime $endDate
8311
 * @param datetime $currentDate
8312
 *
8313
 * @return bool true if date is in rage, false otherwise
8314
 */
8315
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8316
{
8317
    $startDate = strtotime(api_get_local_time($startDate));
8318
    $endDate = strtotime(api_get_local_time($endDate));
8319
    $currentDate = strtotime(api_get_local_time($currentDate));
8320
8321
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8322
        return true;
8323
    }
8324
8325
    return false;
8326
}
8327
8328
/**
8329
 * Eliminate the duplicates of a multidimensional array by sending the key.
8330
 *
8331
 * @param array $array multidimensional array
8332
 * @param int   $key   key to find to compare
8333
 *
8334
 * @return array
8335
 */
8336
function api_unique_multidim_array($array, $key)
8337
{
8338
    $temp_array = [];
8339
    $i = 0;
8340
    $key_array = [];
8341
8342
    foreach ($array as $val) {
8343
        if (!in_array($val[$key], $key_array)) {
8344
            $key_array[$i] = $val[$key];
8345
            $temp_array[$i] = $val;
8346
        }
8347
        $i++;
8348
    }
8349
8350
    return $temp_array;
8351
}
8352
8353
/**
8354
 * Limit the access to Session Admins when the limit_session_admin_role
8355
 * configuration variable is set to true.
8356
 */
8357
function api_protect_limit_for_session_admin()
8358
{
8359
    $limitAdmin = api_get_setting('limit_session_admin_role');
8360
    if (api_is_session_admin() && 'true' === $limitAdmin) {
8361
        api_not_allowed(true);
8362
    }
8363
}
8364
8365
/**
8366
 * Limits that a session admin has access to list users.
8367
 * When limit_session_admin_list_users configuration variable is set to true.
8368
 */
8369
function api_protect_session_admin_list_users()
8370
{
8371
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8372
8373
    if (api_is_session_admin() && true === $limitAdmin) {
8374
        api_not_allowed(true);
8375
    }
8376
}
8377
8378
/**
8379
 * @return bool
8380
 */
8381
function api_is_student_view_active()
8382
{
8383
    $studentView = Session::read('studentview');
8384
8385
    return 'studentview' === $studentView;
8386
}
8387
8388
/**
8389
 * Adds a file inside the upload/$type/id.
8390
 *
8391
 * @param string $type
8392
 * @param array  $file
8393
 * @param int    $itemId
8394
 * @param string $cropParameters
8395
 *
8396
 * @return array|bool
8397
 */
8398
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8399
{
8400
    throw new Exception('api_upload_file not implemented');
8401
    $upload = process_uploaded_file($file);
8402
    if ($upload) {
8403
        $name = api_replace_dangerous_char($file['name']);
8404
8405
        // No "dangerous" files
8406
        $name = disable_dangerous_file($name);
8407
8408
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8409
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8410
8411
        if (!is_dir($path)) {
8412
            mkdir($path, api_get_permissions_for_new_directories(), true);
8413
        }
8414
8415
        $pathToSave = $path.$name;
8416
        $result = moveUploadedFile($file, $pathToSave);
8417
8418
        if ($result) {
8419
            if (!empty($cropParameters)) {
8420
                $image = new Image($pathToSave);
8421
                $image->crop($cropParameters);
8422
            }
8423
8424
            return ['path_to_save' => $pathId.$name];
8425
        }
8426
    }
8427
8428
    return false;
8429
}
8430
8431
/**
8432
 * @param string $type
8433
 * @param int    $itemId
8434
 * @param string $file
8435
 *
8436
 * @return bool
8437
 */
8438
function api_get_uploaded_web_url($type, $itemId, $file)
8439
{
8440
    return api_get_uploaded_file($type, $itemId, $file, true);
8441
}
8442
8443
/**
8444
 * @param string $type
8445
 * @param int    $itemId
8446
 * @param string $file
8447
 * @param bool   $getUrl
8448
 *
8449
 * @return bool
8450
 */
8451
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
8452
{
8453
    $itemId = (int) $itemId;
8454
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8455
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8456
    $file = basename($file);
8457
    $file = $path.'/'.$file;
8458
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8459
        if ($getUrl) {
8460
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
8461
        }
8462
8463
        return $file;
8464
    }
8465
8466
    return false;
8467
}
8468
8469
/**
8470
 * @param string $type
8471
 * @param int    $itemId
8472
 * @param string $file
8473
 * @param string $title
8474
 */
8475
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8476
{
8477
    $file = api_get_uploaded_file($type, $itemId, $file);
8478
    if ($file) {
8479
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8480
            DocumentManager::file_send_for_download($file, true, $title);
8481
            exit;
8482
        }
8483
    }
8484
    api_not_allowed(true);
8485
}
8486
8487
/**
8488
 * @param string $type
8489
 * @param string $file
8490
 */
8491
function api_remove_uploaded_file($type, $file)
8492
{
8493
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8494
    $path = $typePath.'/'.$file;
8495
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8496
        unlink($path);
8497
    }
8498
}
8499
8500
/**
8501
 * @param string $type
8502
 * @param int    $itemId
8503
 * @param string $file
8504
 *
8505
 * @return bool
8506
 */
8507
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8508
{
8509
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8510
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8511
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8512
        unlink($file);
8513
8514
        return true;
8515
    }
8516
8517
    return false;
8518
}
8519
8520
/**
8521
 * Converts string value to float value.
8522
 *
8523
 * 3.141516 => 3.141516
8524
 * 3,141516 => 3.141516
8525
 *
8526
 * @todo WIP
8527
 *
8528
 * @param string $number
8529
 *
8530
 * @return float
8531
 */
8532
function api_float_val($number)
8533
{
8534
    $number = (float) str_replace(',', '.', trim($number));
8535
8536
    return $number;
8537
}
8538
8539
/**
8540
 * Converts float values
8541
 * Example if $decimals = 2.
8542
 *
8543
 * 3.141516 => 3.14
8544
 * 3,141516 => 3,14
8545
 *
8546
 * @param string $number            number in iso code
8547
 * @param int    $decimals
8548
 * @param string $decimalSeparator
8549
 * @param string $thousandSeparator
8550
 *
8551
 * @return bool|string
8552
 */
8553
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8554
{
8555
    $number = api_float_val($number);
8556
8557
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8558
}
8559
8560
/**
8561
 * Set location url with a exit break by default.
8562
 *
8563
 * @param string $url
8564
 * @param bool   $exit
8565
 */
8566
function api_location($url, $exit = true)
8567
{
8568
    header('Location: '.$url);
8569
8570
    if ($exit) {
8571
        exit;
8572
    }
8573
}
8574
8575
/**
8576
 * @return string
8577
 */
8578
function api_get_web_url()
8579
{
8580
    if ('test' === api_get_setting('server_type')) {
8581
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8582
    } else {
8583
        return api_get_path(WEB_PATH).'web/';
8584
    }
8585
}
8586
8587
/**
8588
 * @param string $from
8589
 * @param string $to
8590
 *
8591
 * @return string
8592
 */
8593
function api_get_relative_path($from, $to)
8594
{
8595
    // some compatibility fixes for Windows paths
8596
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
8597
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
8598
    $from = str_replace('\\', '/', $from);
8599
    $to = str_replace('\\', '/', $to);
8600
8601
    $from = explode('/', $from);
8602
    $to = explode('/', $to);
8603
    $relPath = $to;
8604
8605
    foreach ($from as $depth => $dir) {
8606
        // find first non-matching dir
8607
        if ($dir === $to[$depth]) {
8608
            // ignore this directory
8609
            array_shift($relPath);
8610
        } else {
8611
            // get number of remaining dirs to $from
8612
            $remaining = count($from) - $depth;
8613
            if ($remaining > 1) {
8614
                // add traversals up to first matching dir
8615
                $padLength = (count($relPath) + $remaining - 1) * -1;
8616
                $relPath = array_pad($relPath, $padLength, '..');
8617
                break;
8618
            } else {
8619
                $relPath[0] = './'.$relPath[0];
8620
            }
8621
        }
8622
    }
8623
8624
    return implode('/', $relPath);
8625
}
8626
8627
/**
8628
 * Unserialize content using Brummann\Polyfill\Unserialize.
8629
 *
8630
 * @param string $type
8631
 * @param string $serialized
8632
 *
8633
 * @return mixed
8634
 */
8635
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8636
{
8637
    switch ($type) {
8638
        case 'career':
8639
        case 'sequence_graph':
8640
            $allowedClasses = [
8641
                \Fhaculty\Graph\Graph::class,
8642
                \Fhaculty\Graph\Set\VerticesMap::class,
8643
                \Fhaculty\Graph\Set\Vertices::class,
8644
                \Fhaculty\Graph\Set\Edges::class,
8645
            ];
8646
            break;
8647
        case 'lp':
8648
            $allowedClasses = [
8649
                learnpath::class,
8650
                learnpathItem::class,
8651
                aicc::class,
8652
                aiccBlock::class,
8653
                aiccItem::class,
8654
                aiccObjective::class,
8655
                aiccResource::class,
8656
                scorm::class,
8657
                scormItem::class,
8658
                scormMetadata::class,
8659
                scormOrganization::class,
8660
                scormResource::class,
8661
                Link::class,
8662
                LpItem::class,
8663
            ];
8664
            break;
8665
        case 'course':
8666
            $allowedClasses = [
8667
                \Chamilo\CourseBundle\Component\CourseCopy\Course::class,
8668
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement::class,
8669
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance::class,
8670
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent::class,
8671
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath::class,
8672
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory::class,
8673
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription::class,
8674
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession::class,
8675
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Document::class,
8676
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum::class,
8677
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory::class,
8678
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost::class,
8679
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic::class,
8680
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary::class,
8681
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup::class,
8682
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Link::class,
8683
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory::class,
8684
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz::class,
8685
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion::class,
8686
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption::class,
8687
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument::class,
8688
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey::class,
8689
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation::class,
8690
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion::class,
8691
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic::class,
8692
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro::class,
8693
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki::class,
8694
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Work::class,
8695
                stdClass::class,
8696
            ];
8697
            break;
8698
        case 'not_allowed_classes':
8699
        default:
8700
            $allowedClasses = false;
8701
    }
8702
8703
    if ($ignoreErrors) {
8704
        return @UnserializeApi::unserialize(
8705
            $serialized,
8706
            ['allowed_classes' => $allowedClasses]
8707
        );
8708
    }
8709
8710
    return UnserializeApi::unserialize(
8711
        $serialized,
8712
        ['allowed_classes' => $allowedClasses]
8713
    );
8714
}
8715
8716
/**
8717
 * @param string $template
8718
 *
8719
 * @return string
8720
 */
8721
function api_find_template($template)
8722
{
8723
    return Template::findTemplateFilePath($template);
8724
}
8725
8726
/**
8727
 * @return array
8728
 */
8729
function api_get_language_list_for_flag()
8730
{
8731
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
8732
    $sql = "SELECT english_name, isocode FROM $table
8733
            ORDER BY original_name ASC";
8734
    static $languages = [];
8735
    if (empty($languages)) {
8736
        $result = Database::query($sql);
8737
        while ($row = Database::fetch_array($result)) {
8738
            $languages[$row['english_name']] = $row['isocode'];
8739
        }
8740
        $languages['english'] = 'gb';
8741
    }
8742
8743
    return $languages;
8744
}
8745
8746
/**
8747
 * @param string $name
8748
 *
8749
 * @return \ZipStream\ZipStream
8750
 */
8751
function api_create_zip($name)
8752
{
8753
    $zipStreamOptions = new \ZipStream\Option\Archive();
8754
    $zipStreamOptions->setSendHttpHeaders(true);
8755
    $zipStreamOptions->setContentDisposition('attachment');
8756
    $zipStreamOptions->setContentType('application/x-zip');
8757
8758
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
8759
8760
    return $zip;
8761
}
8762
8763
/**
8764
 * @return string
8765
 */
8766
function api_get_language_translate_html()
8767
{
8768
    $translate = api_get_configuration_value('translate_html');
8769
8770
    if (!$translate) {
8771
        return '';
8772
    }
8773
8774
    $languageList = api_get_languages();
8775
    $hideAll = '';
8776
    foreach ($languageList['all'] as $language) {
8777
        $hideAll .= '
8778
        $("span:lang('.$language['isocode'].')").filter(
8779
            function(e, val) {
8780
                // Only find the spans if they have set the lang
8781
                if ($(this).attr("lang") == null) {
8782
                    return false;
8783
                }
8784
8785
                // Ignore ckeditor classes
8786
                return !this.className.match(/cke(.*)/);
8787
        }).hide();'."\n";
8788
    }
8789
8790
    $userInfo = api_get_user_info();
8791
    $languageId = api_get_language_id($userInfo['language']);
8792
    $languageInfo = api_get_language_info($languageId);
8793
    $isoCode = 'en';
8794
8795
    if (!empty($languageInfo)) {
8796
        $isoCode = $languageInfo['isocode'];
8797
    }
8798
8799
    return '
8800
            $(function() {
8801
                '.$hideAll.'
8802
                var defaultLanguageFromUser = "'.$isoCode.'";
8803
8804
                $("span:lang('.$isoCode.')").filter(
8805
                    function() {
8806
                        // Ignore ckeditor classes
8807
                        return !this.className.match(/cke(.*)/);
8808
                }).show();
8809
8810
                var defaultLanguage = "";
8811
                var langFromUserFound = false;
8812
8813
                $(this).find("span").filter(
8814
                    function() {
8815
                        // Ignore ckeditor classes
8816
                        return !this.className.match(/cke(.*)/);
8817
                }).each(function() {
8818
                    defaultLanguage = $(this).attr("lang");
8819
                    if (defaultLanguage) {
8820
                        $(this).before().next("br").remove();
8821
                        if (defaultLanguageFromUser == defaultLanguage) {
8822
                            langFromUserFound = true;
8823
                        }
8824
                    }
8825
                });
8826
8827
                // Show default language
8828
                if (langFromUserFound == false && defaultLanguage) {
8829
                    $("span:lang("+defaultLanguage+")").filter(
8830
                    function() {
8831
                            // Ignore ckeditor classes
8832
                            return !this.className.match(/cke(.*)/);
8833
                    }).show();
8834
                }
8835
            });
8836
    ';
8837
}
8838