Passed
Push — 1.11.x ( 4c1f61...f2253e )
by Julito
09:20
created

apiBlockInactiveUser()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 50
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

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

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

Loading history...
1220
            isset($course_info['registration_code']) && !empty($course_info['registration_code'])
1221
        ) {
1222
            $is_visible = false;
1223
        }
1224
    }
1225
1226
    if (!empty($checkTool)) {
1227
        if (!api_is_allowed_to_edit(true, true, true)) {
1228
            $toolInfo = api_get_tool_information_by_name($checkTool);
1229
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && $toolInfo['visibility'] == 0) {
1230
                api_not_allowed(true);
1231
1232
                return false;
1233
            }
1234
        }
1235
    }
1236
1237
    // Check session visibility
1238
    $session_id = api_get_session_id();
1239
1240
    if (!empty($session_id)) {
1241
        // $isAllowedInCourse was set in local.inc.php
1242
        if (!$isAllowedInCourse) {
1243
            $is_visible = false;
1244
        }
1245
    }
1246
1247
    if (!$is_visible) {
1248
        api_not_allowed($print_headers);
1249
1250
        return false;
1251
    }
1252
1253
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
1254
        $plugin = Positioning::create();
1255
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1256
        if ('true' === $block) {
1257
            $currentPath = $_SERVER['PHP_SELF'];
1258
            // Allowed only this course paths.
1259
            $paths = [
1260
                '/plugin/positioning/start.php',
1261
                '/plugin/positioning/start_student.php',
1262
                '/main/course_home/course_home.php',
1263
                '/main/exercise/overview.php',
1264
            ];
1265
1266
            if (!in_array($currentPath, $paths, true)) {
1267
                // Check if entering an exercise.
1268
                global $current_course_tool;
1269
                if ('quiz' !== $current_course_tool) {
1270
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1271
                    if ($initialData && isset($initialData['exercise_id'])) {
1272
                        $results = Event::getExerciseResultsByUser(
0 ignored issues
show
Bug introduced by
The method getExerciseResultsByUser() does not exist on Event. ( Ignorable by Annotation )

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

1272
                        /** @scrutinizer ignore-call */ 
1273
                        $results = Event::getExerciseResultsByUser(

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

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

Loading history...
1273
                            api_get_user_id(),
1274
                            $initialData['exercise_id'],
1275
                            $course_info['real_id'],
1276
                            $session_id
1277
                        );
1278
                        if (empty($results)) {
1279
                            api_not_allowed($print_headers);
1280
1281
                            return false;
1282
                        }
1283
                    }
1284
                }
1285
            }
1286
        }
1287
    }
1288
1289
    api_block_inactive_user();
1290
1291
    return true;
1292
}
1293
1294
/**
1295
 * Function used to protect an admin script.
1296
 *
1297
 * The function blocks access when the user has no platform admin rights
1298
 * with an error message printed on default output
1299
 *
1300
 * @param bool Whether to allow session admins as well
1301
 * @param bool Whether to allow HR directors as well
1302
 * @param string An optional message (already passed through get_lang)
1303
 *
1304
 * @return bool True if user is allowed, false otherwise.
1305
 *              The function also outputs an error message in case not allowed
1306
 *
1307
 * @author Roan Embrechts (original author)
1308
 */
1309
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1310
{
1311
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1312
        api_not_allowed(true, $message);
1313
1314
        return false;
1315
    }
1316
1317
    api_block_inactive_user();
1318
1319
    return true;
1320
}
1321
1322
/**
1323
 * Blocks inactive users with a currently active session from accessing more pages "live".
1324
 *
1325
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1326
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1327
 */
1328
function api_block_inactive_user()
1329
{
1330
    $data = true;
1331
    if (api_get_configuration_value('security_block_inactive_users_immediately') != 1) {
1332
        return $data;
1333
    }
1334
1335
    $userId = api_get_user_id();
1336
    $homeUrl = api_get_path(WEB_PATH);
1337
    if ($userId == 0) {
1338
        return $data;
1339
    }
1340
1341
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1342
            WHERE id = $userId";
1343
1344
    $result = Database::query($sql);
1345
    if (Database::num_rows($result) > 0) {
1346
        $result_array = Database::fetch_array($result);
1347
        $data = (bool) $result_array['active'];
1348
    }
1349
    if ($data == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1350
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1351
        $tpl->assign('hide_login_link', 1);
1352
1353
        //api_not_allowed(true, get_lang('AccountInactive'));
1354
        // we were not in a course, return to home page
1355
        $msg = Display::return_message(
1356
            get_lang('AccountInactive'),
1357
            'error',
1358
            false
1359
        );
1360
1361
        $msg .= '<p class="text-center">
1362
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1363
1364
        if (api_is_anonymous()) {
1365
            $form = api_get_not_allowed_login_form();
1366
            $msg .= '<div class="well">';
1367
            $msg .= $form->returnForm();
1368
            $msg .= '</div>';
1369
        }
1370
1371
        $tpl->assign('content', $msg);
1372
        $tpl->display_one_col_template();
1373
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
1374
    }
1375
1376
    return $data;
1377
}
1378
1379
/**
1380
 * Function used to protect a teacher script.
1381
 * The function blocks access when the user has no teacher rights.
1382
 *
1383
 * @return bool True if the current user can access the script, false otherwise
1384
 *
1385
 * @author Yoselyn Castillo
1386
 */
1387
function api_protect_teacher_script()
1388
{
1389
    if (!api_is_allowed_to_edit()) {
1390
        api_not_allowed(true);
1391
1392
        return false;
1393
    }
1394
1395
    return true;
1396
}
1397
1398
/**
1399
 * Function used to prevent anonymous users from accessing a script.
1400
 *
1401
 * @param bool|true $printHeaders
1402
 *
1403
 * @author Roan Embrechts
1404
 *
1405
 * @return bool
1406
 */
1407
function api_block_anonymous_users($printHeaders = true)
1408
{
1409
    $user = api_get_user_info();
1410
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1411
        api_not_allowed($printHeaders);
1412
1413
        return false;
1414
    }
1415
    apiBlockInactiveUser();
0 ignored issues
show
Bug introduced by
The function apiBlockInactiveUser was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1415
    /** @scrutinizer ignore-call */ 
1416
    apiBlockInactiveUser();
Loading history...
1416
1417
    return true;
1418
}
1419
1420
/**
1421
 * Returns a rough evaluation of the browser's name and version based on very
1422
 * simple regexp.
1423
 *
1424
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1425
 */
1426
function api_get_navigator()
1427
{
1428
    $navigator = 'Unknown';
1429
    $version = 0;
1430
1431
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1432
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1433
    }
1434
1435
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1436
        $navigator = 'Opera';
1437
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1438
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1439
        $navigator = 'Edge';
1440
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1441
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1442
        $navigator = 'Internet Explorer';
1443
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1444
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1445
        $navigator = 'Chrome';
1446
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1447
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1448
        $navigator = 'Safari';
1449
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1450
            // If this Safari does have the "Version/" string in its user agent
1451
            // then use that as a version indicator rather than what's after
1452
            // "Safari/" which is rather a "build number" or something
1453
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1454
        } else {
1455
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1456
        }
1457
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1458
        $navigator = 'Firefox';
1459
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1460
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1461
        $navigator = 'Netscape';
1462
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1463
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1464
        } else {
1465
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1466
        }
1467
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1468
        $navigator = 'Konqueror';
1469
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1470
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1471
        $navigator = 'AppleWebKit';
1472
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1473
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1474
        $navigator = 'Mozilla';
1475
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1476
    }
1477
1478
    // Now cut extra stuff around (mostly *after*) the version number
1479
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1480
1481
    if (strpos($version, '.') === false) {
1482
        $version = number_format(doubleval($version), 1);
1483
    }
1484
1485
    return ['name' => $navigator, 'version' => $version];
1486
}
1487
1488
/**
1489
 * @return true if user self registration is allowed, false otherwise
1490
 */
1491
function api_is_self_registration_allowed()
1492
{
1493
    return isset($GLOBALS['allowSelfReg']) ? $GLOBALS['allowSelfReg'] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $GLOB...'allowSelfReg'] : false could also return false which is incompatible with the documented return type true. Did you maybe forget to handle an error condition?

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

Loading history...
1494
}
1495
1496
/**
1497
 * This function returns the id of the user which is stored in the $_user array.
1498
 *
1499
 * example: The function can be used to check if a user is logged in
1500
 *          if (api_get_user_id())
1501
 *
1502
 * @return int the id of the current user, 0 if is empty
1503
 */
1504
function api_get_user_id()
1505
{
1506
    $userInfo = Session::read('_user');
1507
    if ($userInfo && isset($userInfo['user_id'])) {
1508
        return (int) $userInfo['user_id'];
1509
    }
1510
1511
    return 0;
1512
}
1513
1514
/**
1515
 * Gets the list of courses a specific user is subscribed to.
1516
 *
1517
 * @param int       User ID
1518
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1519
 *
1520
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1521
 *
1522
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1523
 */
1524
function api_get_user_courses($userId, $fetch_session = true)
1525
{
1526
    // Get out if not integer
1527
    if ($userId != strval(intval($userId))) {
1528
        return [];
1529
    }
1530
1531
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1532
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1533
1534
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1535
            FROM $t_course cc, $t_course_user cu
1536
            WHERE
1537
                cc.id = cu.c_id AND
1538
                cu.user_id = $userId AND
1539
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1540
    $result = Database::query($sql);
1541
    if ($result === false) {
1542
        return [];
1543
    }
1544
1545
    $courses = [];
1546
    while ($row = Database::fetch_array($result)) {
1547
        // we only need the database name of the course
1548
        $courses[] = $row;
1549
    }
1550
1551
    return $courses;
1552
}
1553
1554
/**
1555
 * Formats user information into a standard array
1556
 * This function should be only used inside api_get_user_info().
1557
 *
1558
 * @param array Non-standard user array
0 ignored issues
show
Documentation Bug introduced by
The doc comment Non-standard at position 0 could not be parsed: Unknown type name 'Non-standard' at position 0 in Non-standard.
Loading history...
1559
 * @param bool $add_password
1560
 * @param bool $loadAvatars  turn off to improve performance
1561
 *
1562
 * @return array Standard user array
1563
 */
1564
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1565
{
1566
    $result = [];
1567
1568
    $result['firstname'] = null;
1569
    $result['lastname'] = null;
1570
1571
    if (isset($user['firstname']) && isset($user['lastname'])) { // with only lowercase
1572
        $result['firstname'] = $user['firstname'];
1573
        $result['lastname'] = $user['lastname'];
1574
    } elseif (isset($user['firstName']) && isset($user['lastName'])) { // with uppercase letters
1575
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1576
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1577
    }
1578
1579
    if (isset($user['email'])) {
1580
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1581
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1582
    } else {
1583
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1584
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1585
    }
1586
1587
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1588
    $result['complete_name_with_username'] = $result['complete_name'];
1589
1590
    if (!empty($user['username']) && !api_get_configuration_value('hide_username_with_complete_name')) {
1591
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1592
    }
1593
1594
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1595
    if (!empty($user['email'])) {
1596
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1597
        if ($showEmail) {
1598
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1599
        }
1600
    } else {
1601
        $result['complete_name_with_email'] = $result['complete_name'];
1602
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1603
    }
1604
1605
    // Kept for historical reasons
1606
    $result['firstName'] = $result['firstname'];
1607
    $result['lastName'] = $result['lastname'];
1608
1609
    $attributes = [
1610
        'phone',
1611
        'address',
1612
        'picture_uri',
1613
        'official_code',
1614
        'status',
1615
        'active',
1616
        'auth_source',
1617
        'username',
1618
        'theme',
1619
        'language',
1620
        'creator_id',
1621
        'registration_date',
1622
        'hr_dept_id',
1623
        'expiration_date',
1624
        'last_login',
1625
        'user_is_online',
1626
    ];
1627
1628
    if (api_get_setting('extended_profile') === 'true') {
1629
        $attributes[] = 'competences';
1630
        $attributes[] = 'diplomas';
1631
        $attributes[] = 'teach';
1632
        $attributes[] = 'openarea';
1633
    }
1634
1635
    foreach ($attributes as $attribute) {
1636
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1637
    }
1638
1639
    $user_id = (int) $user['user_id'];
1640
    // Maintain the user_id index for backwards compatibility
1641
    $result['user_id'] = $result['id'] = $user_id;
1642
1643
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1644
    $result['has_certificates'] = 0;
1645
    if (!empty($hasCertificates)) {
1646
        $result['has_certificates'] = 1;
1647
    }
1648
1649
    $result['icon_status'] = '';
1650
    $result['icon_status_medium'] = '';
1651
1652
    $result['is_admin'] = UserManager::is_admin($user_id);
1653
1654
    // Getting user avatar.
1655
    if ($loadAvatars) {
1656
        $result['avatar'] = '';
1657
        $result['avatar_no_query'] = '';
1658
        $result['avatar_small'] = '';
1659
        $result['avatar_medium'] = '';
1660
1661
        if (!isset($user['avatar'])) {
1662
            $originalFile = UserManager::getUserPicture(
1663
                $user_id,
1664
                USER_IMAGE_SIZE_ORIGINAL,
1665
                null,
1666
                $result
1667
            );
1668
            $result['avatar'] = $originalFile;
1669
            $avatarString = explode('?', $result['avatar']);
1670
            $result['avatar_no_query'] = reset($avatarString);
1671
        } else {
1672
            $result['avatar'] = $user['avatar'];
1673
            $avatarString = explode('?', $user['avatar']);
1674
            $result['avatar_no_query'] = reset($avatarString);
1675
        }
1676
1677
        if (!isset($user['avatar_small'])) {
1678
            $smallFile = UserManager::getUserPicture(
1679
                $user_id,
1680
                USER_IMAGE_SIZE_SMALL,
1681
                null,
1682
                $result
1683
            );
1684
            $result['avatar_small'] = $smallFile;
1685
        } else {
1686
            $result['avatar_small'] = $user['avatar_small'];
1687
        }
1688
1689
        if (!isset($user['avatar_medium'])) {
1690
            $mediumFile = UserManager::getUserPicture(
1691
                $user_id,
1692
                USER_IMAGE_SIZE_MEDIUM,
1693
                null,
1694
                $result
1695
            );
1696
            $result['avatar_medium'] = $mediumFile;
1697
        } else {
1698
            $result['avatar_medium'] = $user['avatar_medium'];
1699
        }
1700
1701
        $urlImg = api_get_path(WEB_IMG_PATH);
1702
        $iconStatus = '';
1703
        $iconStatusMedium = '';
1704
        $label = '';
1705
        switch ($result['status']) {
1706
            case STUDENT:
1707
                if ($result['has_certificates']) {
1708
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1709
                    $label = get_lang('Graduated');
1710
                } else {
1711
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1712
                    $label = get_lang('Student');
1713
                }
1714
                break;
1715
            case COURSEMANAGER:
1716
                if ($result['is_admin']) {
1717
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1718
                    $label = get_lang('Admin');
1719
                } else {
1720
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1721
                    $label = get_lang('Teacher');
1722
                }
1723
                break;
1724
            case STUDENT_BOSS:
1725
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1726
                $label = get_lang('StudentBoss');
1727
                break;
1728
        }
1729
1730
        if (!empty($iconStatus)) {
1731
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1732
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1733
        }
1734
1735
        $result['icon_status'] = $iconStatus;
1736
        $result['icon_status_label'] = $label;
1737
        $result['icon_status_medium'] = $iconStatusMedium;
1738
    }
1739
1740
    if (isset($user['user_is_online'])) {
1741
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1742
    }
1743
    if (isset($user['user_is_online_in_chat'])) {
1744
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1745
    }
1746
1747
    if ($add_password) {
1748
        $result['password'] = $user['password'];
1749
    }
1750
1751
    if (isset($result['profile_completed'])) {
1752
        $result['profile_completed'] = $user['profile_completed'];
1753
    }
1754
1755
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1756
1757
    // Send message link
1758
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1759
    $result['complete_name_with_message_link'] = Display::url(
1760
        $result['complete_name_with_username'],
1761
        $sendMessage,
1762
        ['class' => 'ajax']
1763
    );
1764
1765
    if (isset($user['extra'])) {
1766
        $result['extra'] = $user['extra'];
1767
    }
1768
1769
    return $result;
1770
}
1771
1772
/**
1773
 * Finds all the information about a user.
1774
 * If no parameter is passed you find all the information about the current user.
1775
 *
1776
 * @param int  $user_id
1777
 * @param bool $checkIfUserOnline
1778
 * @param bool $showPassword
1779
 * @param bool $loadExtraData
1780
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1781
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1782
 * @param bool $updateCache              update apc cache if exists
1783
 *
1784
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1785
 *
1786
 * @author Patrick Cool <[email protected]>
1787
 * @author Julio Montoya
1788
 *
1789
 * @version 21 September 2004
1790
 */
1791
function api_get_user_info(
1792
    $user_id = 0,
1793
    $checkIfUserOnline = false,
1794
    $showPassword = false,
1795
    $loadExtraData = false,
1796
    $loadOnlyVisibleExtraData = false,
1797
    $loadAvatars = true,
1798
    $updateCache = false
1799
) {
1800
    $apcVar = null;
1801
    $user = false;
1802
    $cacheAvailable = api_get_configuration_value('apc');
1803
1804
    if (empty($user_id)) {
1805
        $userFromSession = Session::read('_user');
1806
1807
        if (isset($userFromSession)) {
1808
            if ($cacheAvailable === true &&
1809
                (
1810
                    empty($userFromSession['is_anonymous']) &&
1811
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1812
                )
1813
            ) {
1814
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1815
                if (apcu_exists($apcVar)) {
1816
                    if ($updateCache) {
1817
                        apcu_store($apcVar, $userFromSession, 60);
1818
                    }
1819
                    $user = apcu_fetch($apcVar);
1820
                } else {
1821
                    $user = _api_format_user(
1822
                        $userFromSession,
1823
                        $showPassword,
1824
                        $loadAvatars
1825
                    );
1826
                    apcu_store($apcVar, $user, 60);
1827
                }
1828
            } else {
1829
                $user = _api_format_user(
1830
                    $userFromSession,
1831
                    $showPassword,
1832
                    $loadAvatars
1833
                );
1834
            }
1835
1836
            return $user;
1837
        }
1838
1839
        return false;
1840
    }
1841
1842
    // Make sure user_id is safe
1843
    $user_id = (int) $user_id;
1844
1845
    // Re-use user information if not stale and already stored in APCu
1846
    if ($cacheAvailable === true) {
1847
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1848
        if (apcu_exists($apcVar) && $updateCache == false && $checkIfUserOnline == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1849
            $user = apcu_fetch($apcVar);
1850
1851
            return $user;
1852
        }
1853
    }
1854
1855
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1856
            WHERE id = $user_id";
1857
    $result = Database::query($sql);
1858
    if (Database::num_rows($result) > 0) {
1859
        $result_array = Database::fetch_array($result);
1860
        $result_array['user_is_online_in_chat'] = 0;
1861
        if ($checkIfUserOnline) {
1862
            $use_status_in_platform = user_is_online($user_id);
1863
            $result_array['user_is_online'] = $use_status_in_platform;
1864
            $user_online_in_chat = 0;
1865
            if ($use_status_in_platform) {
1866
                $user_status = UserManager::get_extra_user_data_by_field(
1867
                    $user_id,
1868
                    'user_chat_status',
1869
                    false,
1870
                    true
1871
                );
1872
                if ((int) $user_status['user_chat_status'] == 1) {
1873
                    $user_online_in_chat = 1;
1874
                }
1875
            }
1876
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1877
        }
1878
1879
        if ($loadExtraData) {
1880
            $fieldValue = new ExtraFieldValue('user');
1881
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1882
                $user_id,
1883
                $loadOnlyVisibleExtraData
1884
            );
1885
        }
1886
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1887
    }
1888
1889
    if ($cacheAvailable === true) {
1890
        apcu_store($apcVar, $user, 60);
1891
    }
1892
1893
    return $user;
1894
}
1895
1896
/**
1897
 * @param int $userId
1898
 *
1899
 * @return User
1900
 */
1901
function api_get_user_entity($userId)
1902
{
1903
    $userId = (int) $userId;
1904
    $repo = UserManager::getRepository();
1905
1906
    /** @var User $user */
1907
    $user = $repo->find($userId);
1908
1909
    return $user;
1910
}
1911
1912
/**
1913
 * Finds all the information about a user from username instead of user id.
1914
 *
1915
 * @param string $username
1916
 *
1917
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1918
 *
1919
 * @author Yannick Warnier <[email protected]>
1920
 */
1921
function api_get_user_info_from_username($username)
1922
{
1923
    if (empty($username)) {
1924
        return false;
1925
    }
1926
    $username = trim($username);
1927
1928
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1929
            WHERE username='".Database::escape_string($username)."'";
1930
    $result = Database::query($sql);
1931
    if (Database::num_rows($result) > 0) {
1932
        $resultArray = Database::fetch_array($result);
1933
1934
        return _api_format_user($resultArray);
1935
    }
1936
1937
    return false;
1938
}
1939
1940
/**
1941
 * Get first user with an email.
1942
 *
1943
 * @param string $email
1944
 *
1945
 * @return array|bool
1946
 */
1947
function api_get_user_info_from_email($email = '')
1948
{
1949
    if (empty($email)) {
1950
        return false;
1951
    }
1952
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1953
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1954
    $result = Database::query($sql);
1955
    if (Database::num_rows($result) > 0) {
1956
        $resultArray = Database::fetch_array($result);
1957
1958
        return _api_format_user($resultArray);
1959
    }
1960
1961
    return false;
1962
}
1963
1964
/**
1965
 * @return string
1966
 */
1967
function api_get_course_id()
1968
{
1969
    return Session::read('_cid', null);
1970
}
1971
1972
/**
1973
 * Returns the current course id (integer).
1974
 *
1975
 * @param string $code Optional course code
1976
 *
1977
 * @return int
1978
 */
1979
function api_get_course_int_id($code = null)
1980
{
1981
    if (!empty($code)) {
1982
        $code = Database::escape_string($code);
1983
        $row = Database::select(
1984
            'id',
1985
            Database::get_main_table(TABLE_MAIN_COURSE),
1986
            ['where' => ['code = ?' => [$code]]],
1987
            'first'
1988
        );
1989
1990
        if (is_array($row) && isset($row['id'])) {
1991
            return $row['id'];
1992
        } else {
1993
            return false;
1994
        }
1995
    }
1996
1997
    return Session::read('_real_cid', 0);
1998
}
1999
2000
/**
2001
 * Returns the current course directory.
2002
 *
2003
 * This function relies on api_get_course_info()
2004
 *
2005
 * @param string    The course code - optional (takes it from session if not given)
2006
 *
2007
 * @return string The directory where the course is located inside the Chamilo "courses" directory
2008
 *
2009
 * @author Yannick Warnier <[email protected]>
2010
 */
2011
function api_get_course_path($course_code = null)
2012
{
2013
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
2014
2015
    return $info['path'];
2016
}
2017
2018
/**
2019
 * Gets a course setting from the current course_setting table. Try always using integer values.
2020
 *
2021
 * @param string $settingName The name of the setting we want from the table
2022
 * @param array  $courseInfo
2023
 * @param bool   $force       force checking the value in the database
2024
 *
2025
 * @return mixed The value of that setting in that table. Return -1 if not found.
2026
 */
2027
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
2028
{
2029
    if (empty($courseInfo)) {
2030
        $courseInfo = api_get_course_info();
2031
    }
2032
2033
    if (empty($courseInfo) || empty($settingName)) {
2034
        return -1;
2035
    }
2036
2037
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2038
2039
    if (empty($courseId)) {
2040
        return -1;
2041
    }
2042
2043
    static $courseSettingInfo = [];
2044
2045
    if ($force) {
2046
        $courseSettingInfo = [];
2047
    }
2048
2049
    if (!isset($courseSettingInfo[$courseId])) {
2050
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2051
        $settingName = Database::escape_string($settingName);
2052
2053
        $sql = "SELECT variable, value FROM $table
2054
                WHERE c_id = $courseId ";
2055
        $res = Database::query($sql);
2056
        if (Database::num_rows($res) > 0) {
2057
            $result = Database::store_result($res, 'ASSOC');
2058
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2059
2060
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2061
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2062
                if (!is_null($value)) {
2063
                    $result = explode(',', $value);
2064
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2065
                }
2066
            }
2067
        }
2068
    }
2069
2070
    if (isset($courseSettingInfo[$courseId]) && array_key_exists($settingName, $courseSettingInfo[$courseId])) {
2071
        return $courseSettingInfo[$courseId][$settingName];
2072
    }
2073
2074
    return -1;
2075
}
2076
2077
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2078
{
2079
    $value = api_get_course_setting($settingName, $courseInfo, true);
2080
2081
    if (-1 === $value) {
2082
        // Check global settings
2083
        $value = api_get_plugin_setting($plugin, $settingName);
2084
        if ($value === 'true') {
2085
            return 1;
2086
        }
2087
        if ($value === 'false') {
2088
            return 0;
2089
        }
2090
        if (null === $value) {
2091
            return -1;
2092
        }
2093
    }
2094
2095
    return $value;
2096
}
2097
2098
/**
2099
 * Gets an anonymous user ID.
2100
 *
2101
 * For some tools that need tracking, like the learnpath tool, it is necessary
2102
 * to have a usable user-id to enable some kind of tracking, even if not
2103
 * perfect. An anonymous ID is taken from the users table by looking for a
2104
 * status of "6" (anonymous).
2105
 *
2106
 * @return int User ID of the anonymous user, or O if no anonymous user found
2107
 */
2108
function api_get_anonymous_id()
2109
{
2110
    // Find if another anon is connected now
2111
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2112
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2113
    $ip = Database::escape_string(api_get_real_ip());
2114
    $max = (int) api_get_configuration_value('max_anonymous_users');
2115
    if ($max >= 2) {
2116
        $sql = "SELECT * FROM $table as TEL
2117
                JOIN $tableU as U
2118
                ON U.user_id = TEL.login_user_id
2119
                WHERE TEL.user_ip = '$ip'
2120
                    AND U.status = ".ANONYMOUS."
2121
                    AND U.user_id != 2 ";
2122
2123
        $result = Database::query($sql);
2124
        if (empty(Database::num_rows($result))) {
2125
            $login = uniqid('anon_');
2126
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2127
            if (count($anonList) >= $max) {
2128
                foreach ($anonList as $userToDelete) {
2129
                    UserManager::delete_user($userToDelete['user_id']);
2130
                    break;
2131
                }
2132
            }
2133
            // Return the user ID
2134
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...lhost', $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

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

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

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

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

Loading history...
3706
        case SESSION_INVISIBLE:
3707
            return false;
3708
    }
3709
3710
    return false;
3711
}
3712
3713
/**
3714
 * Checks if a student can edit contents in a session depending
3715
 * on the session visibility.
3716
 *
3717
 * @param bool $tutor Whether to check if the user has the tutor role
3718
 * @param bool $coach Whether to check if the user has the coach role
3719
 *
3720
 * @return bool true: the user has the rights to edit, false: he does not
3721
 */
3722
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3723
{
3724
    if (api_is_allowed_to_edit($tutor, $coach)) {
3725
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3726
        return true;
3727
    } else {
3728
        $sessionId = api_get_session_id();
3729
3730
        if (0 == $sessionId) {
3731
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3732
            return true;
3733
        } else {
3734
            // I'm in a session and I'm a student
3735
            // Get the session visibility
3736
            $session_visibility = api_get_session_visibility($sessionId);
3737
            // if 5 the session is still available
3738
            switch ($session_visibility) {
3739
                case SESSION_VISIBLE_READ_ONLY: // 1
3740
                    return false;
3741
                case SESSION_VISIBLE:           // 2
3742
                    return true;
3743
                case SESSION_INVISIBLE:         // 3
3744
                    return false;
3745
                case SESSION_AVAILABLE:         //5
3746
                    return true;
3747
            }
3748
        }
3749
    }
3750
3751
    return false;
3752
}
3753
3754
/**
3755
 * Checks whether the user is allowed in a specific tool for a specific action.
3756
 *
3757
 * @param string $tool   the tool we are checking if the user has a certain permission
3758
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3759
 *
3760
 * @return bool
3761
 *
3762
 * @author Patrick Cool <[email protected]>, Ghent University
3763
 * @author Julio Montoya
3764
 *
3765
 * @version 1.0
3766
 */
3767
function api_is_allowed($tool, $action, $task_id = 0)
3768
{
3769
    $_user = api_get_user_info();
3770
    $_course = api_get_course_info();
3771
3772
    if (api_is_course_admin()) {
3773
        return true;
3774
    }
3775
3776
    if (is_array($_course) and count($_course) > 0) {
3777
        require_once __DIR__.'/../../permissions/permissions_functions.inc.php';
3778
3779
        // Getting the permissions of this user.
3780
        if ($task_id == 0) {
3781
            $user_permissions = get_permissions('user', $_user['user_id']);
3782
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3783
        }
3784
3785
        // Getting the permissions of the task.
3786
        if ($task_id != 0) {
3787
            $task_permissions = get_permissions('task', $task_id);
3788
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3789
        }
3790
        //print_r($_SESSION['total_permissions']);
3791
3792
        // Getting the permissions of the groups of the user
3793
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3794
3795
        //foreach($groups_of_user as $group)
3796
        //   $this_group_permissions = get_permissions('group', $group);
3797
3798
        // Getting the permissions of the courseroles of the user
3799
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3800
3801
        // Getting the permissions of the platformroles of the user
3802
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3803
3804
        // Getting the permissions of the roles of the groups of the user
3805
        //foreach($groups_of_user as $group)
3806
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3807
3808
        // Getting the permissions of the platformroles of the groups of the user
3809
        //foreach($groups_of_user as $group)
3810
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3811
    }
3812
3813
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3814
    if (api_get_setting('permissions') == 'limited') {
3815
        if ($action == 'Visibility') {
3816
            $action = 'Edit';
3817
        }
3818
        if ($action == 'Move') {
3819
            $action = 'Edit';
3820
        }
3821
    }
3822
3823
    // The session that contains all the permissions already exists for this course
3824
    // so there is no need to requery everything.
3825
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3826
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3827
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3828
            return true;
3829
        } else {
3830
            return false;
3831
        }
3832
    }
3833
3834
    return false;
3835
}
3836
3837
/**
3838
 * Tells whether this user is an anonymous user.
3839
 *
3840
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3841
 * @param bool $db_check Whether to check in the database (true) or simply in
3842
 *                       the session (false) to see if the current user is the anonymous user
3843
 *
3844
 * @return bool true if this user is anonymous, false otherwise
3845
 */
3846
function api_is_anonymous($user_id = null, $db_check = false)
3847
{
3848
    if (!isset($user_id)) {
3849
        $user_id = api_get_user_id();
3850
    }
3851
3852
    if ($db_check) {
3853
        $info = api_get_user_info($user_id);
3854
        if (false === $info || $info['status'] == ANONYMOUS) {
3855
            return true;
3856
        }
3857
    }
3858
3859
    $_user = api_get_user_info();
3860
3861
    if (isset($_user['status']) && $_user['status'] == ANONYMOUS) {
3862
        //if ($_user['user_id'] == 0) {
3863
        // In some cases, api_set_anonymous doesn't seem to be triggered in local.inc.php. Make sure it is.
3864
        // Occurs in agenda for admin links - YW
3865
        global $use_anonymous;
3866
        if (isset($use_anonymous) && $use_anonymous) {
3867
            api_set_anonymous();
3868
        }
3869
3870
        return true;
3871
    }
3872
3873
    return (isset($_user['is_anonymous']) && $_user['is_anonymous'] === true) || $_user === false;
3874
}
3875
3876
/**
3877
 * Displays message "You are not allowed here..." and exits the entire script.
3878
 *
3879
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3880
 * @param string $message
3881
 * @param int    $responseCode
3882
 */
3883
function api_not_allowed(
3884
    $print_headers = false,
3885
    $message = null,
3886
    $responseCode = 0
3887
) {
3888
    if (api_get_setting('sso_authentication') === 'true') {
3889
        global $osso;
3890
        if ($osso) {
3891
            $osso->logout();
3892
        }
3893
    }
3894
    $home_url = api_get_path(WEB_PATH);
3895
    $user_id = api_get_user_id();
3896
    $course = api_get_course_id();
3897
3898
    global $this_section;
3899
3900
    if (CustomPages::enabled() && !isset($user_id)) {
3901
        if (empty($user_id)) {
3902
            // Why the CustomPages::enabled() need to be to set the request_uri
3903
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3904
        }
3905
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3906
    }
3907
3908
    $origin = api_get_origin();
3909
3910
    $msg = null;
3911
    if (isset($message)) {
3912
        $msg = $message;
3913
    } else {
3914
        $msg = Display::return_message(
3915
            get_lang('NotAllowedClickBack').'
3916
            <script>function goBack(){window.history.back();}</script>',
3917
            'error',
3918
            false
3919
        );
3920
        $msg .= '<p class="text-center">
3921
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3922
             </p>';
3923
    }
3924
3925
    $msg = Display::div($msg, ['align' => 'center']);
3926
3927
    $show_headers = 0;
3928
    if ($print_headers && $origin != 'learnpath') {
3929
        $show_headers = 1;
3930
    }
3931
3932
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3933
    $tpl->assign('hide_login_link', 1);
3934
    $tpl->assign('content', $msg);
3935
3936
    if (($user_id != 0 && !api_is_anonymous()) &&
3937
        (!isset($course) || $course == -1) &&
3938
        empty($_GET['cidReq'])
3939
    ) {
3940
        // if the access is not authorized and there is some login information
3941
        // but the cidReq is not found, assume we are missing course data and send the user
3942
        // to the user_portal
3943
        $tpl->display_one_col_template();
3944
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
3945
    }
3946
3947
    if (!empty($_SERVER['REQUEST_URI']) &&
3948
        (
3949
            !empty($_GET['cidReq']) ||
3950
            $this_section == SECTION_MYPROFILE ||
3951
            $this_section == SECTION_PLATFORM_ADMIN
3952
        )
3953
    ) {
3954
        $courseCode = api_get_course_id();
3955
        // Only display form and return to the previous URL if there was a course ID included
3956
        if ($user_id != 0 && !api_is_anonymous()) {
3957
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3958
            $tpl->assign('content', $msg);
3959
            $tpl->display_one_col_template();
3960
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
3961
        }
3962
3963
        if (!is_null($courseCode)) {
3964
            api_set_firstpage_parameter($courseCode);
3965
        }
3966
3967
        // If the user has no user ID, then his session has expired
3968
        $form = api_get_not_allowed_login_form();
3969
3970
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3971
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3972
3973
        if (!empty($courseCode)) {
3974
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3975
        }
3976
3977
        if (api_is_cas_activated()) {
3978
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
3979
            $content .= Display::div(
3980
                Template::displayCASLoginButton(),
3981
                ['align' => 'center']
3982
            );
3983
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3984
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3985
            $content .= "<div style='display:none;'>";
3986
        }
3987
        $content .= '<div class="well">';
3988
        $content .= $form->returnForm();
3989
        $content .= '</div>';
3990
        if (api_is_cas_activated()) {
3991
            $content .= "</div>";
3992
        }
3993
3994
        if (!empty($courseCode)) {
3995
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3996
                get_lang('ReturnToCourseHomepage').'</a></p>';
3997
        } else {
3998
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3999
                get_lang('BackHome').'</a></p>';
4000
        }
4001
4002
        $tpl->setLoginBodyClass();
4003
        $tpl->assign('content', $content);
4004
        $tpl->display_one_col_template();
4005
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
4006
    }
4007
4008
    if ($user_id != 0 && !api_is_anonymous()) {
4009
        $tpl->display_one_col_template();
4010
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
4011
    }
4012
4013
    $msg = null;
4014
    // The session is over and we were not in a course,
4015
    // or we try to get directly to a private course without being logged
4016
    $courseId = api_get_course_int_id();
4017
    if (!empty($courseId)) {
4018
        api_set_firstpage_parameter(api_get_course_id());
4019
        $tpl->setLoginBodyClass();
4020
4021
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
4022
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
4023
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
4024
        $casEnabled = api_is_cas_activated();
4025
        if ($casEnabled) {
4026
            $msg .= Display::return_message(
4027
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
4028
                '',
4029
                false
4030
            );
4031
            $msg .= Display::div(
4032
                Template::displayCASLoginButton(),
4033
                ['align' => 'center']
4034
            );
4035
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
4036
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
4037
            $msg .= "<div style='display:none;'>";
4038
        }
4039
        $form = api_get_not_allowed_login_form();
4040
        $msg .= '<div class="well">';
4041
        $msg .= $form->returnForm();
4042
        $msg .= '</div>';
4043
        if ($casEnabled) {
4044
            $msg .= "</div>";
4045
        }
4046
    } else {
4047
        // we were not in a course, return to home page
4048
        $msg = Display::return_message(
4049
            get_lang('NotAllowed'),
4050
            'error',
4051
            false
4052
        );
4053
4054
        $msg .= '<p class="text-center">
4055
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
4056
                 </p>';
4057
4058
        if (!empty($message)) {
4059
            $msg = $message;
4060
        }
4061
4062
        if (api_is_anonymous()) {
4063
            $form = api_get_not_allowed_login_form();
4064
            $msg .= '<div class="well">';
4065
            $msg .= $form->returnForm();
4066
            $msg .= '</div>';
4067
        }
4068
    }
4069
4070
    $tpl->assign('content', $msg);
4071
    $tpl->display_one_col_template();
4072
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
4073
}
4074
4075
/**
4076
 * @return FormValidator
4077
 */
4078
function api_get_not_allowed_login_form()
4079
{
4080
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
4081
    $action = str_replace('&amp;', '&', $action);
4082
    Session::write('redirect_after_not_allow_page', $action);
4083
    $action .= '&redirect_after_not_allow_page=1';
4084
4085
    $form = new FormValidator(
4086
        'formLogin',
4087
        'post',
4088
        $action,
4089
        null,
4090
        ['class' => 'form-stacked']
4091
    );
4092
    $params = [
4093
        'placeholder' => get_lang('UserName'),
4094
        'class' => 'col-md-3',
4095
    ];
4096
    if (api_browser_support('autocapitalize')) {
4097
        $params['autocapitalize'] = 'none';
4098
    }
4099
4100
    $form->addElement(
4101
        'text',
4102
        'login',
4103
        null,
4104
        $params
4105
    );
4106
    $form->addElement(
4107
        'password',
4108
        'password',
4109
        null,
4110
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
4111
    ); //new
4112
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
4113
4114
    return $form;
4115
}
4116
4117
/**
4118
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
4119
 *
4120
 * @param string $last_post_datetime standard output date in a sql query
4121
 *
4122
 * @return int timestamp
4123
 *
4124
 * @author Toon Van Hoecke <[email protected]>
4125
 *
4126
 * @version October 2003
4127
 * @desc convert sql date to unix timestamp
4128
 */
4129
function convert_sql_date($last_post_datetime)
4130
{
4131
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
4132
    list($year, $month, $day) = explode('-', $last_post_date);
4133
    list($hour, $min, $sec) = explode(':', $last_post_time);
4134
4135
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
4136
}
4137
4138
/**
4139
 * Gets item visibility from the item_property table.
4140
 *
4141
 * Getting the visibility is done by getting the last updated visibility entry,
4142
 * using the largest session ID found if session 0 and another was found (meaning
4143
 * the only one that is actually from the session, in case there are results from
4144
 * session 0 *AND* session n).
4145
 *
4146
 * @param array  $_course  Course properties array (result of api_get_course_info())
4147
 * @param string $tool     Tool (learnpath, document, etc)
4148
 * @param int    $id       The item ID in the given tool
4149
 * @param int    $session  The session ID (optional)
4150
 * @param int    $user_id
4151
 * @param string $type
4152
 * @param string $group_id
4153
 *
4154
 * @return int -1 on error, 0 if invisible, 1 if visible
4155
 */
4156
function api_get_item_visibility(
4157
    $_course,
4158
    $tool,
4159
    $id,
4160
    $session = 0,
4161
    $user_id = null,
4162
    $type = null,
4163
    $group_id = null
4164
) {
4165
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4166
        return -1;
4167
    }
4168
4169
    $tool = Database::escape_string($tool);
4170
    $id = (int) $id;
4171
    $session = (int) $session;
4172
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4173
    $course_id = (int) $_course['real_id'];
4174
4175
    $userCondition = '';
4176
    if (!empty($user_id)) {
4177
        $user_id = (int) $user_id;
4178
        $userCondition = " AND to_user_id = $user_id ";
4179
    }
4180
4181
    $typeCondition = '';
4182
    if (!empty($type)) {
4183
        $type = Database::escape_string($type);
4184
        $typeCondition = " AND lastedit_type = '$type' ";
4185
    }
4186
4187
    $groupCondition = '';
4188
    if (!empty($group_id)) {
4189
        $group_id = (int) $group_id;
4190
        $groupCondition = " AND to_group_id = '$group_id' ";
4191
    }
4192
4193
    $sql = "SELECT visibility
4194
            FROM $TABLE_ITEMPROPERTY
4195
            WHERE
4196
                c_id = $course_id AND
4197
                tool = '$tool' AND
4198
                ref = $id AND
4199
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4200
                $userCondition $typeCondition $groupCondition
4201
            ORDER BY session_id DESC, lastedit_date DESC
4202
            LIMIT 1";
4203
4204
    $res = Database::query($sql);
4205
    if ($res === false || Database::num_rows($res) == 0) {
4206
        return -1;
4207
    }
4208
    $row = Database::fetch_array($res);
4209
4210
    return (int) $row['visibility'];
4211
}
4212
4213
/**
4214
 * Delete a row in the c_item_property table.
4215
 *
4216
 * @param array  $courseInfo
4217
 * @param string $tool
4218
 * @param int    $itemId
4219
 * @param int    $userId
4220
 * @param int    $groupId    group.iid
4221
 * @param int    $sessionId
4222
 *
4223
 * @return false|null
4224
 */
4225
function api_item_property_delete(
4226
    $courseInfo,
4227
    $tool,
4228
    $itemId,
4229
    $userId,
4230
    $groupId = 0,
4231
    $sessionId = 0
4232
) {
4233
    if (empty($courseInfo)) {
4234
        return false;
4235
    }
4236
4237
    $courseId = (int) $courseInfo['real_id'];
4238
4239
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4240
        return false;
4241
    }
4242
4243
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4244
    $tool = Database::escape_string($tool);
4245
    $itemId = intval($itemId);
4246
    $userId = intval($userId);
4247
    $groupId = intval($groupId);
4248
    $sessionId = intval($sessionId);
4249
4250
    $groupCondition = " AND to_group_id = $groupId ";
4251
    if (empty($groupId)) {
4252
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4253
    }
4254
4255
    $userCondition = " AND to_user_id = $userId ";
4256
    if (empty($userId)) {
4257
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4258
    }
4259
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4260
    $sql = "DELETE FROM $table
4261
            WHERE
4262
                c_id = $courseId AND
4263
                tool  = '$tool' AND
4264
                ref = $itemId
4265
                $sessionCondition
4266
                $userCondition
4267
                $groupCondition
4268
            ";
4269
4270
    Database::query($sql);
4271
}
4272
4273
/**
4274
 * Updates or adds item properties to the Item_propetry table
4275
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4276
 *
4277
 * @param array  $_course        array with course properties
4278
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4279
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4280
 * @param string $last_edit_type add or update action
4281
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4282
 *                               (2) "delete"
4283
 *                               (3) "visible"
4284
 *                               (4) "invisible"
4285
 * @param int    $user_id        id of the editing/adding user
4286
 * @param array  $groupInfo      must include group.iid/group.od
4287
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4288
 * @param string $start_visible  0000-00-00 00:00:00 format
4289
 * @param string $end_visible    0000-00-00 00:00:00 format
4290
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4291
 *
4292
 * @return bool false if update fails
4293
 *
4294
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4295
 *
4296
 * @version January 2005
4297
 * @desc update the item_properties table (if entry not exists, insert) of the course
4298
 */
4299
function api_item_property_update(
4300
    $_course,
4301
    $tool,
4302
    $item_id,
4303
    $last_edit_type,
4304
    $user_id,
4305
    $groupInfo = [],
4306
    $to_user_id = null,
4307
    $start_visible = '',
4308
    $end_visible = '',
4309
    $session_id = 0
4310
) {
4311
    if (empty($_course)) {
4312
        return false;
4313
    }
4314
4315
    $course_id = $_course['real_id'];
4316
4317
    if (empty($course_id)) {
4318
        return false;
4319
    }
4320
4321
    $to_group_id = 0;
4322
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4323
        $to_group_id = (int) $groupInfo['iid'];
4324
    }
4325
4326
    $em = Database::getManager();
4327
4328
    // Definition of variables.
4329
    $tool = Database::escape_string($tool);
4330
    $item_id = (int) $item_id;
4331
    $lastEditTypeNoFilter = $last_edit_type;
4332
    $last_edit_type = Database::escape_string($last_edit_type);
4333
    $user_id = (int) $user_id;
4334
4335
    $startVisible = "NULL";
4336
    if (!empty($start_visible)) {
4337
        $start_visible = Database::escape_string($start_visible);
4338
        $startVisible = "'$start_visible'";
4339
    }
4340
4341
    $endVisible = "NULL";
4342
    if (!empty($end_visible)) {
4343
        $end_visible = Database::escape_string($end_visible);
4344
        $endVisible = "'$end_visible'";
4345
    }
4346
4347
    $to_filter = '';
4348
    $time = api_get_utc_datetime();
4349
4350
    if (!empty($session_id)) {
4351
        $session_id = (int) $session_id;
4352
    } else {
4353
        $session_id = api_get_session_id();
4354
    }
4355
4356
    // Definition of tables.
4357
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4358
4359
    if ($to_user_id <= 0) {
4360
        $to_user_id = null; // No to_user_id set
4361
    }
4362
4363
    if (!is_null($to_user_id)) {
4364
        // $to_user_id has more priority than $to_group_id
4365
        $to_user_id = (int) $to_user_id;
4366
        $to_field = 'to_user_id';
4367
        $to_value = $to_user_id;
4368
    } else {
4369
        // $to_user_id is not set.
4370
        $to_field = 'to_group_id';
4371
        $to_value = $to_group_id;
4372
    }
4373
4374
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4375
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4376
    $condition_session = " AND session_id = $session_id ";
4377
    if (empty($session_id)) {
4378
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4379
    }
4380
4381
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4382
4383
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4384
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4385
    if (is_null($to_user_id) && is_null($to_group_id)) {
4386
        $to_group_id = 0;
4387
    }
4388
4389
    if (!is_null($to_user_id)) {
4390
        // Set filter to intended user.
4391
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4392
    } else {
4393
        // Set filter to intended group.
4394
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4395
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4396
        }
4397
    }
4398
4399
    // Adding filter if set.
4400
    $filter .= $to_filter;
4401
4402
    // Update if possible
4403
    $set_type = '';
4404
4405
    switch ($lastEditTypeNoFilter) {
4406
        case 'delete':
4407
            // delete = make item only visible for the platform admin.
4408
            $visibility = '2';
4409
            if (!empty($session_id)) {
4410
                // Check whether session id already exist into item_properties for updating visibility or add it.
4411
                $sql = "SELECT session_id FROM $tableItemProperty
4412
                        WHERE
4413
                            c_id = $course_id AND
4414
                            tool = '$tool' AND
4415
                            ref = $item_id AND
4416
                            session_id = $session_id";
4417
                $rs = Database::query($sql);
4418
                if (Database::num_rows($rs) > 0) {
4419
                    $sql = "UPDATE $tableItemProperty
4420
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4421
                                lastedit_date       = '$time',
4422
                                lastedit_user_id    = $user_id,
4423
                                visibility          = $visibility,
4424
                                session_id          = $session_id $set_type
4425
                            WHERE $filter";
4426
                    $result = Database::query($sql);
4427
                } else {
4428
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id, $to_field, visibility, start_visible, end_visible, session_id)
4429
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4430
                    $result = Database::query($sql);
4431
                    $id = Database::insert_id();
4432
                    if ($id) {
4433
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4434
                        Database::query($sql);
4435
                    }
4436
                }
4437
            } else {
4438
                $sql = "UPDATE $tableItemProperty
4439
                        SET
4440
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4441
                            lastedit_date='$time',
4442
                            lastedit_user_id = $user_id,
4443
                            visibility = $visibility $set_type
4444
                        WHERE $filter";
4445
                $result = Database::query($sql);
4446
            }
4447
            break;
4448
        case 'visible': // Change item to visible.
4449
            $visibility = '1';
4450
            if (!empty($session_id)) {
4451
                // Check whether session id already exist into item_properties for updating visibility or add it.
4452
                $sql = "SELECT session_id FROM $tableItemProperty
4453
                        WHERE
4454
                            c_id = $course_id AND
4455
                            tool = '$tool' AND
4456
                            ref = $item_id AND
4457
                            session_id = $session_id";
4458
                $rs = Database::query($sql);
4459
                if (Database::num_rows($rs) > 0) {
4460
                    $sql = "UPDATE $tableItemProperty
4461
                            SET
4462
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4463
                                lastedit_date='$time',
4464
                                lastedit_user_id = $user_id,
4465
                                visibility = $visibility,
4466
                                session_id = $session_id $set_type
4467
                            WHERE $filter";
4468
                    $result = Database::query($sql);
4469
                } else {
4470
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id, $to_field, visibility, start_visible, end_visible, session_id)
4471
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4472
                    $result = Database::query($sql);
4473
                    $id = Database::insert_id();
4474
                    if ($id) {
4475
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4476
                        Database::query($sql);
4477
                    }
4478
                }
4479
            } else {
4480
                $sql = "UPDATE $tableItemProperty
4481
                        SET
4482
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4483
                            lastedit_date='$time',
4484
                            lastedit_user_id = $user_id,
4485
                            visibility = $visibility $set_type
4486
                        WHERE $filter";
4487
                $result = Database::query($sql);
4488
            }
4489
            break;
4490
        case 'invisible': // Change item to invisible.
4491
            $visibility = '0';
4492
            if (!empty($session_id)) {
4493
                // Check whether session id already exist into item_properties for updating visibility or add it
4494
                $sql = "SELECT session_id FROM $tableItemProperty
4495
                        WHERE
4496
                            c_id = $course_id AND
4497
                            tool = '$tool' AND
4498
                            ref = $item_id AND
4499
                            session_id = $session_id";
4500
                $rs = Database::query($sql);
4501
                if (Database::num_rows($rs) > 0) {
4502
                    $sql = "UPDATE $tableItemProperty
4503
                            SET
4504
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4505
                                lastedit_date = '$time',
4506
                                lastedit_user_id = $user_id,
4507
                                visibility = $visibility,
4508
                                session_id = $session_id $set_type
4509
                            WHERE $filter";
4510
                    $result = Database::query($sql);
4511
                } else {
4512
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id,$to_field, visibility, start_visible, end_visible, session_id)
4513
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4514
                    $result = Database::query($sql);
4515
                    $id = Database::insert_id();
4516
                    if ($id) {
4517
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4518
                        Database::query($sql);
4519
                    }
4520
                }
4521
            } else {
4522
                $sql = "UPDATE $tableItemProperty
4523
                        SET
4524
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4525
                            lastedit_date = '$time',
4526
                            lastedit_user_id = $user_id,
4527
                            visibility = $visibility $set_type
4528
                        WHERE $filter";
4529
                $result = Database::query($sql);
4530
            }
4531
            break;
4532
        default: // The item will be added or updated.
4533
            $set_type = ", lastedit_type = '$last_edit_type' ";
4534
            $visibility = '1';
4535
            //$filter .= $to_filter; already added
4536
            $sql = "UPDATE $tableItemProperty
4537
                    SET
4538
                      lastedit_date = '$time',
4539
                      lastedit_user_id = $user_id $set_type
4540
                    WHERE $filter";
4541
            $result = Database::query($sql);
4542
    }
4543
4544
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4545
    if ($result == false || Database::affected_rows($result) == 0) {
4546
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4547
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4548
        $objUser = api_get_user_entity($user_id);
4549
        if (empty($objUser)) {
4550
            // Use anonymous
4551
            $user_id = api_get_anonymous_id();
4552
            $objUser = api_get_user_entity($user_id);
4553
        }
4554
4555
        $objGroup = null;
4556
        if (!empty($to_group_id)) {
4557
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4558
        }
4559
4560
        $objToUser = api_get_user_entity($to_user_id);
4561
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4562
4563
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4564
        $endVisibleDate = !empty($endVisibleDate) ? new DateTime($endVisibleDate, new DateTimeZone('UTC')) : null;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $endVisibleDate seems to never exist and therefore empty should always be true.
Loading history...
4565
4566
        $cItemProperty = new CItemProperty($objCourse);
4567
        $cItemProperty
4568
            ->setTool($tool)
4569
            ->setRef($item_id)
4570
            ->setInsertDate($objTime)
4571
            ->setInsertUser($objUser)
4572
            ->setLasteditDate($objTime)
4573
            ->setLasteditType($last_edit_type)
4574
            ->setGroup($objGroup)
4575
            ->setToUser($objToUser)
4576
            ->setVisibility($visibility)
4577
            ->setStartVisible($startVisibleDate)
4578
            ->setEndVisible($endVisibleDate)
4579
            ->setSession($objSession);
4580
4581
        $em->persist($cItemProperty);
4582
        $em->flush();
4583
4584
        $id = $cItemProperty->getIid();
4585
4586
        if ($id) {
4587
            $cItemProperty->setId($id);
4588
            $em->merge($cItemProperty);
4589
            $em->flush();
4590
4591
            return false;
4592
        }
4593
    }
4594
4595
    return true;
4596
}
4597
4598
/**
4599
 * Gets item property by tool.
4600
 *
4601
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4602
 * @param string $course_code
4603
 * @param int    $session_id
4604
 *
4605
 * @return array All fields from c_item_property (all rows found) or empty array
4606
 */
4607
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4608
{
4609
    $course_info = api_get_course_info($course_code);
4610
    $tool = Database::escape_string($tool);
4611
4612
    // Definition of tables.
4613
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4614
    $session_id = (int) $session_id;
4615
    $session_condition = ' AND session_id = '.$session_id;
4616
    if (empty($session_id)) {
4617
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4618
    }
4619
    $course_id = $course_info['real_id'];
4620
4621
    $sql = "SELECT * FROM $item_property_table
4622
            WHERE
4623
                c_id = $course_id AND
4624
                tool = '$tool'
4625
                $session_condition ";
4626
    $rs = Database::query($sql);
4627
    $list = [];
4628
    if (Database::num_rows($rs) > 0) {
4629
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4630
            $list[] = $row;
4631
        }
4632
    }
4633
4634
    return $list;
4635
}
4636
4637
/**
4638
 * Gets item property by tool and user.
4639
 *
4640
 * @param int $userId
4641
 * @param int $tool
4642
 * @param int $courseId
4643
 * @param int $session_id
4644
 *
4645
 * @return array
4646
 */
4647
function api_get_item_property_list_by_tool_by_user(
4648
    $userId,
4649
    $tool,
4650
    $courseId,
4651
    $session_id = 0
4652
) {
4653
    $userId = intval($userId);
4654
    $tool = Database::escape_string($tool);
4655
    $session_id = intval($session_id);
4656
    $courseId = intval($courseId);
4657
4658
    // Definition of tables.
4659
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4660
    $session_condition = ' AND session_id = '.$session_id;
4661
    if (empty($session_id)) {
4662
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4663
    }
4664
    $sql = "SELECT * FROM $item_property_table
4665
            WHERE
4666
                insert_user_id = $userId AND
4667
                c_id = $courseId AND
4668
                tool = '$tool'
4669
                $session_condition ";
4670
4671
    $rs = Database::query($sql);
4672
    $list = [];
4673
    if (Database::num_rows($rs) > 0) {
4674
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4675
            $list[] = $row;
4676
        }
4677
    }
4678
4679
    return $list;
4680
}
4681
4682
/**
4683
 * Gets item property id from tool of a course.
4684
 *
4685
 * @param string $course_code course code
4686
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4687
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4688
 * @param int    $sessionId   Session ID (optional)
4689
 *
4690
 * @return int
4691
 */
4692
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4693
{
4694
    $course_info = api_get_course_info($course_code);
4695
    $tool = Database::escape_string($tool);
4696
    $ref = (int) $ref;
4697
4698
    // Definition of tables.
4699
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4700
    $course_id = $course_info['real_id'];
4701
    $sessionId = (int) $sessionId;
4702
    $sessionCondition = " AND session_id = $sessionId ";
4703
    if (empty($sessionId)) {
4704
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4705
    }
4706
    $sql = "SELECT id FROM $tableItemProperty
4707
            WHERE
4708
                c_id = $course_id AND
4709
                tool = '$tool' AND
4710
                ref = $ref
4711
                $sessionCondition";
4712
    $rs = Database::query($sql);
4713
    $item_property_id = '';
4714
    if (Database::num_rows($rs) > 0) {
4715
        $row = Database::fetch_array($rs);
4716
        $item_property_id = $row['id'];
4717
    }
4718
4719
    return $item_property_id;
4720
}
4721
4722
/**
4723
 * Inserts a record in the track_e_item_property table (No update).
4724
 *
4725
 * @param string $tool
4726
 * @param int    $ref
4727
 * @param string $title
4728
 * @param string $content
4729
 * @param int    $progress
4730
 *
4731
 * @return bool|int
4732
 */
4733
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4734
{
4735
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4736
    $course_id = api_get_course_int_id(); //numeric
4737
    $course_code = api_get_course_id(); //alphanumeric
4738
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4739
    if (!empty($item_property_id)) {
4740
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4741
                course_id           = '$course_id',
4742
                item_property_id    = '$item_property_id',
4743
                title               = '".Database::escape_string($title)."',
4744
                content             = '".Database::escape_string($content)."',
4745
                progress            = '".intval($progress)."',
4746
                lastedit_date       = '".api_get_utc_datetime()."',
4747
                lastedit_user_id    = '".api_get_user_id()."',
4748
                session_id          = '".api_get_session_id()."'";
4749
        $result = Database::query($sql);
4750
        $affected_rows = Database::affected_rows($result);
4751
4752
        return $affected_rows;
4753
    }
4754
4755
    return false;
4756
}
4757
4758
/**
4759
 * @param string $tool
4760
 * @param int    $ref
4761
 *
4762
 * @return array|resource
4763
 */
4764
function api_get_track_item_property_history($tool, $ref)
4765
{
4766
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4767
    $course_id = api_get_course_int_id(); //numeric
4768
    $course_code = api_get_course_id(); //alphanumeric
4769
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4770
    $sql = "SELECT * FROM $tbl_stats_item_property
4771
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4772
            ORDER BY lastedit_date DESC";
4773
    $result = Database::query($sql);
4774
    if ($result === false or $result === null) {
4775
        $result = [];
4776
    } else {
4777
        $result = Database::store_result($result, 'ASSOC');
4778
    }
4779
4780
    return $result;
4781
}
4782
4783
/**
4784
 * Gets item property data from tool of a course id.
4785
 *
4786
 * @param int    $course_id
4787
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4788
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4789
 * @param int    $session_id
4790
 * @param int    $groupId
4791
 *
4792
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4793
 */
4794
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4795
{
4796
    $courseInfo = api_get_course_info_by_id($course_id);
4797
4798
    if (empty($courseInfo)) {
4799
        return false;
4800
    }
4801
4802
    $tool = Database::escape_string($tool);
4803
    $course_id = $courseInfo['real_id'];
4804
    $ref = (int) $ref;
4805
    $session_id = (int) $session_id;
4806
4807
    $sessionCondition = " session_id = $session_id";
4808
    if (empty($session_id)) {
4809
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4810
    }
4811
4812
    // Definition of tables.
4813
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4814
4815
    $sql = "SELECT * FROM $table
4816
            WHERE
4817
                c_id = $course_id AND
4818
                tool = '$tool' AND
4819
                ref = $ref AND
4820
                $sessionCondition ";
4821
4822
    if (!empty($groupId)) {
4823
        $groupId = (int) $groupId;
4824
        $sql .= " AND to_group_id = $groupId ";
4825
    }
4826
4827
    $rs = Database::query($sql);
4828
    $row = [];
4829
    if (Database::num_rows($rs) > 0) {
4830
        $row = Database::fetch_array($rs, 'ASSOC');
4831
    }
4832
4833
    return $row;
4834
}
4835
4836
/**
4837
 * Displays a combo box so the user can select his/her preferred language.
4838
 *
4839
 * @param string The desired name= value for the select
4840
 * @param bool Whether we use the JQuery Chozen library or not
4841
 * (in some cases, like the indexing language picker, it can alter the presentation)
4842
 *
4843
 * @return string
4844
 */
4845
function api_get_languages_combo($name = 'language')
4846
{
4847
    $ret = '';
4848
    $platformLanguage = api_get_setting('platformLanguage');
4849
4850
    // Retrieve a complete list of all the languages.
4851
    $language_list = api_get_languages();
4852
4853
    if (count($language_list['name']) < 2) {
4854
        return $ret;
4855
    }
4856
4857
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4858
    if (isset($_SESSION['user_language_choice'])) {
4859
        $default = $_SESSION['user_language_choice'];
4860
    } else {
4861
        $default = $platformLanguage;
4862
    }
4863
4864
    $languages = $language_list['name'];
4865
    $folder = $language_list['folder'];
4866
4867
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker form-control">';
4868
    foreach ($languages as $key => $value) {
4869
        if ($folder[$key] == $default) {
4870
            $selected = ' selected="selected"';
4871
        } else {
4872
            $selected = '';
4873
        }
4874
        $ret .= sprintf('<option value=%s" %s>%s</option>', $folder[$key], $selected, $value);
4875
    }
4876
    $ret .= '</select>';
4877
4878
    return $ret;
4879
}
4880
4881
/**
4882
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4883
 * The form works with or without javascript.
4884
 *
4885
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4886
 * @param bool $showAsButton
4887
 *
4888
 * @return string|null Display the box directly
4889
 */
4890
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4891
{
4892
    // Retrieve a complete list of all the languages.
4893
    $language_list = api_get_languages();
4894
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4895
        return null; //don't show any form
4896
    }
4897
4898
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4899
    if (isset($_SESSION['user_language_choice'])) {
4900
        $user_selected_language = $_SESSION['user_language_choice'];
4901
    }
4902
    if (empty($user_selected_language)) {
4903
        $user_selected_language = api_get_setting('platformLanguage');
4904
    }
4905
4906
    $currentLanguageId = api_get_language_id($user_selected_language);
4907
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4908
4909
    $countryCode = languageCodeToCountryIsoCodeForFlags($currentLanguageInfo['isocode']);
4910
    $url = api_get_self();
4911
    if ($showAsButton) {
4912
        $html = '<div class="btn-group">
4913
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4914
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4915
                '.$currentLanguageInfo['original_name'].'
4916
                <span class="caret">
4917
                </span>
4918
              </button>';
4919
    } else {
4920
        $html = '
4921
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4922
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4923
                '.$currentLanguageInfo['original_name'].'
4924
                <span class="caret"></span>
4925
            </a>
4926
            ';
4927
    }
4928
4929
    $html .= '<ul class="dropdown-menu" role="menu">';
4930
    foreach ($language_list['all'] as $key => $data) {
4931
        $urlLink = $url.'?language='.$data['english_name'];
4932
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageCodeToCountryIsoCodeForFlags($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4933
    }
4934
    $html .= '</ul>';
4935
4936
    if ($showAsButton) {
4937
        $html .= '</div>';
4938
    }
4939
4940
    return $html;
4941
}
4942
4943
/**
4944
 * Return a country code based on a language in order to show a country flag.
4945
 * Note: Showing a "language" flag is arguably a bad idea, as several countries
4946
 * share languages and the right flag cannot be shown for all of them.
4947
 *
4948
 * @param string $languageIsoCode
4949
 *
4950
 * @return string
4951
 */
4952
function languageCodeToCountryIsoCodeForFlags($languageIsoCode)
4953
{
4954
    $allow = api_get_configuration_value('language_flags_by_country');
4955
4956
    // @todo save in DB
4957
    switch ($languageIsoCode) {
4958
        case 'ar':
4959
            $country = 'ae';
4960
            break;
4961
        case 'bs':
4962
            $country = 'ba';
4963
            break;
4964
        case 'ca':
4965
            $country = 'es';
4966
            if ($allow) {
4967
                $country = 'catalan';
4968
            }
4969
            break;
4970
        case 'cs':
4971
            $country = 'cz';
4972
            break;
4973
        case 'da':
4974
            $country = 'dk';
4975
            break;
4976
        case 'el':
4977
            $country = 'ae';
4978
            break;
4979
        case 'en':
4980
            $country = 'gb';
4981
            break;
4982
        case 'eu': // Euskera
4983
            $country = 'es';
4984
            if ($allow) {
4985
                $country = 'basque';
4986
            }
4987
            break;
4988
        case 'gl': // galego
4989
            $country = 'es';
4990
            if ($allow) {
4991
                $country = 'galician';
4992
            }
4993
            break;
4994
        case 'he':
4995
            $country = 'il';
4996
            break;
4997
        case 'ja':
4998
            $country = 'jp';
4999
            break;
5000
        case 'ka':
5001
            $country = 'ge';
5002
            break;
5003
        case 'ko':
5004
            $country = 'kr';
5005
            break;
5006
        case 'ms':
5007
            $country = 'my';
5008
            break;
5009
        case 'pt-BR':
5010
            $country = 'br';
5011
            break;
5012
        case 'qu':
5013
            $country = 'pe';
5014
            break;
5015
        case 'sl':
5016
            $country = 'si';
5017
            break;
5018
        case 'sv':
5019
            $country = 'se';
5020
            break;
5021
        case 'uk': // Ukraine
5022
            $country = 'ua';
5023
            break;
5024
        case 'zh-TW':
5025
        case 'zh':
5026
            $country = 'cn';
5027
            break;
5028
        default:
5029
            $country = $languageIsoCode;
5030
            break;
5031
    }
5032
    $country = strtolower($country);
5033
5034
    return $country;
5035
}
5036
5037
/**
5038
 * Returns a list of all the languages that are made available by the admin.
5039
 *
5040
 * @return array An array with all languages. Structure of the array is
5041
 *               array['name'] = An array with the name of every language
5042
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
5043
 */
5044
function api_get_languages()
5045
{
5046
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5047
    $sql = "SELECT * FROM $tbl_language WHERE available='1'
5048
            ORDER BY original_name ASC";
5049
    $result = Database::query($sql);
5050
    $language_list = [];
5051
    while ($row = Database::fetch_array($result)) {
5052
        $language_list['name'][] = $row['original_name'];
5053
        $language_list['folder'][] = $row['dokeos_folder'];
5054
        $language_list['all'][] = $row;
5055
    }
5056
5057
    return $language_list;
5058
}
5059
5060
/**
5061
 * Returns a list of all the languages that are made available by the admin.
5062
 *
5063
 * @return array
5064
 */
5065
function api_get_languages_to_array()
5066
{
5067
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5068
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
5069
    $result = Database::query($sql);
5070
    $languages = [];
5071
    while ($row = Database::fetch_array($result)) {
5072
        $languages[$row['dokeos_folder']] = $row['original_name'];
5073
    }
5074
5075
    return $languages;
5076
}
5077
5078
/**
5079
 * Returns the id (the database id) of a language.
5080
 *
5081
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
5082
 *
5083
 * @return int id of the language
5084
 */
5085
function api_get_language_id($language)
5086
{
5087
    if (empty($language)) {
5088
        return null;
5089
    }
5090
5091
    static $staticResult;
5092
5093
    if (isset($staticResult[$language])) {
5094
        return $staticResult[$language];
5095
    } else {
5096
        $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5097
        $language = Database::escape_string($language);
5098
        $sql = "SELECT id FROM $table
5099
                WHERE dokeos_folder = '$language' LIMIT 1";
5100
        $result = Database::query($sql);
5101
        $row = Database::fetch_array($result);
5102
5103
        $staticResult[$language] = $row['id'];
5104
5105
        return $row['id'];
5106
    }
5107
}
5108
5109
/**
5110
 * Gets language of the requested type for the current user. Types are :
5111
 * user_profil_lang : profile language of current user
5112
 * user_select_lang : language selected by user at login
5113
 * course_lang : language of the current course
5114
 * platform_lang : default platform language.
5115
 *
5116
 * @param string $lang_type
5117
 *
5118
 * @return string
5119
 */
5120
function api_get_language_from_type($lang_type)
5121
{
5122
    $return = false;
5123
    switch ($lang_type) {
5124
        case 'platform_lang':
5125
            $temp_lang = api_get_setting('platformLanguage');
5126
            if (!empty($temp_lang)) {
5127
                $return = $temp_lang;
5128
            }
5129
            break;
5130
        case 'user_profil_lang':
5131
            $_user = api_get_user_info();
5132
            if (isset($_user['language']) && !empty($_user['language'])) {
5133
                $return = $_user['language'];
5134
            }
5135
            break;
5136
        case 'user_selected_lang':
5137
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
5138
                $return = $_SESSION['user_language_choice'];
5139
            }
5140
            break;
5141
        case 'course_lang':
5142
            global $_course;
5143
            $cidReq = null;
5144
            if (empty($_course)) {
5145
                // Code modified because the local.inc.php file it's declarated after this work
5146
                // causing the function api_get_course_info() returns a null value
5147
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
5148
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
5149
                if (empty($cidReq) && !empty($cDir)) {
5150
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
5151
                    if ($c) {
5152
                        $cidReq = $c;
5153
                    }
5154
                }
5155
            }
5156
            $_course = api_get_course_info($cidReq);
5157
            if (isset($_course['language']) && !empty($_course['language'])) {
5158
                $return = $_course['language'];
5159
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
5160
                if ($showCourseInUserLanguage == 1) {
5161
                    $userInfo = api_get_user_info();
5162
                    if (isset($userInfo['language'])) {
5163
                        $return = $userInfo['language'];
5164
                    }
5165
                }
5166
            }
5167
            break;
5168
        default:
5169
            $return = false;
5170
            break;
5171
    }
5172
5173
    return $return;
5174
}
5175
5176
/**
5177
 * Get the language information by its id.
5178
 *
5179
 * @param int $languageId
5180
 *
5181
 * @throws Exception
5182
 *
5183
 * @return array
5184
 */
5185
function api_get_language_info($languageId)
5186
{
5187
    if (empty($languageId)) {
5188
        return [];
5189
    }
5190
5191
    $language = Database::getManager()
5192
        ->find('ChamiloCoreBundle:Language', $languageId);
5193
5194
    if (!$language) {
5195
        return [];
5196
    }
5197
5198
    return [
5199
        'id' => $language->getId(),
5200
        'original_name' => $language->getOriginalName(),
5201
        'english_name' => $language->getEnglishName(),
5202
        'isocode' => $language->getIsocode(),
5203
        'dokeos_folder' => $language->getDokeosFolder(),
5204
        'available' => $language->getAvailable(),
5205
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
5206
    ];
5207
}
5208
5209
/**
5210
 * Returns the name of the visual (CSS) theme to be applied on the current page.
5211
 * The returned name depends on the platform, course or user -wide settings.
5212
 *
5213
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
5214
 */
5215
function api_get_visual_theme()
5216
{
5217
    static $visual_theme;
5218
5219
    // If call from CLI it should be reload.
5220
    if ('cli' === PHP_SAPI) {
5221
        $visual_theme = null;
5222
    }
5223
5224
    if (!isset($visual_theme)) {
5225
        $cacheAvailable = api_get_configuration_value('apc');
5226
        $userThemeAvailable = api_get_setting('user_selected_theme') == 'true';
5227
        $courseThemeAvailable = api_get_setting('allow_course_theme') == 'true';
5228
        // only use a shared cache if no user-based or course-based theme is allowed
5229
        $useCache = ($cacheAvailable && !$userThemeAvailable && !$courseThemeAvailable);
5230
        $apcVar = '';
5231
        if ($useCache) {
5232
            $apcVar = api_get_configuration_value('apc_prefix').'my_campus_visual_theme';
5233
            if (apcu_exists($apcVar)) {
5234
                return apcu_fetch($apcVar);
5235
            }
5236
        }
5237
5238
        $accessUrlId = api_get_current_access_url_id();
5239
        if ('cli' === PHP_SAPI) {
5240
            $accessUrlId = api_get_configuration_value('access_url');
5241
        }
5242
5243
        // Get style directly from DB
5244
        $styleFromDatabase = api_get_settings_params_simple(
5245
            [
5246
                'variable = ? AND access_url = ?' => [
5247
                    'stylesheets',
5248
                    $accessUrlId,
5249
                ],
5250
            ]
5251
        );
5252
        if ($styleFromDatabase) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $styleFromDatabase of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
5253
            $platform_theme = $styleFromDatabase['selected_value'];
5254
        } else {
5255
            $platform_theme = api_get_setting('stylesheets');
5256
        }
5257
5258
        // Platform's theme.
5259
        $visual_theme = $platform_theme;
5260
        if ($userThemeAvailable) {
5261
            $user_info = api_get_user_info();
5262
            if (isset($user_info['theme'])) {
5263
                $user_theme = $user_info['theme'];
5264
5265
                if (!empty($user_theme)) {
5266
                    $visual_theme = $user_theme;
5267
                    // User's theme.
5268
                }
5269
            }
5270
        }
5271
5272
        $course_id = api_get_course_id();
5273
        if (!empty($course_id)) {
5274
            if ($courseThemeAvailable) {
5275
                $course_theme = api_get_course_setting('course_theme', api_get_course_info());
5276
5277
                if (!empty($course_theme) && $course_theme != -1) {
5278
                    if (!empty($course_theme)) {
5279
                        // Course's theme.
5280
                        $visual_theme = $course_theme;
5281
                    }
5282
                }
5283
5284
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5285
                if ($allow_lp_theme == 1) {
5286
                    global $lp_theme_css, $lp_theme_config;
5287
                    // These variables come from the file lp_controller.php.
5288
                    if (!$lp_theme_config) {
5289
                        if (!empty($lp_theme_css)) {
5290
                            // LP's theme.
5291
                            $visual_theme = $lp_theme_css;
5292
                        }
5293
                    }
5294
                }
5295
            }
5296
        }
5297
5298
        if (empty($visual_theme)) {
5299
            $visual_theme = 'chamilo';
5300
        }
5301
5302
        global $lp_theme_log;
5303
        if ($lp_theme_log) {
5304
            $visual_theme = $platform_theme;
5305
        }
5306
        if ($useCache) {
5307
            apcu_store($apcVar, $visual_theme, 120);
5308
        }
5309
    }
5310
5311
    return $visual_theme;
5312
}
5313
5314
/**
5315
 * Returns a list of CSS themes currently available in the CSS folder
5316
 * The folder must have a default.css file.
5317
 *
5318
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5319
 *
5320
 * @return array list of themes directories from the css folder
5321
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5322
 */
5323
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5324
{
5325
    // This configuration value is set by the vchamilo plugin
5326
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5327
5328
    $readCssFolder = function ($dir) use ($virtualTheme) {
5329
        $finder = new Finder();
5330
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5331
        $list = [];
5332
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5333
        foreach ($themes as $theme) {
5334
            $folder = $theme->getFilename();
5335
            // A theme folder is consider if there's a default.css file
5336
            if (!file_exists($theme->getPathname().'/default.css')) {
5337
                continue;
5338
            }
5339
            $name = ucwords(str_replace('_', ' ', $folder));
5340
            if ($folder == $virtualTheme) {
5341
                continue;
5342
            }
5343
            $list[$folder] = $name;
5344
        }
5345
5346
        return $list;
5347
    };
5348
5349
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5350
    $list = $readCssFolder($dir);
5351
5352
    if (!empty($virtualTheme)) {
5353
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5354
        if ($getOnlyThemeFromVirtualInstance) {
5355
            return $newList;
5356
        }
5357
        $list = $list + $newList;
5358
        asort($list);
5359
    }
5360
5361
    return $list;
5362
}
5363
5364
/**
5365
 * Find the largest sort value in a given user_course_category
5366
 * This function is used when we are moving a course to a different category
5367
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5368
 *
5369
 * @author Patrick Cool <[email protected]>, Ghent University
5370
 *
5371
 * @param int $user_course_category the id of the user_course_category
5372
 * @param int $user_id
5373
 *
5374
 * @return int the value of the highest sort of the user_course_category
5375
 */
5376
function api_max_sort_value($user_course_category, $user_id)
5377
{
5378
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5379
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5380
            WHERE
5381
                user_id='".intval($user_id)."' AND
5382
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5383
                user_course_cat='".intval($user_course_category)."'";
5384
    $result_max = Database::query($sql);
5385
    if (Database::num_rows($result_max) == 1) {
5386
        $row_max = Database::fetch_array($result_max);
5387
5388
        return $row_max['max_sort'];
5389
    }
5390
5391
    return 0;
5392
}
5393
5394
/**
5395
 * Transforms a number of seconds in hh:mm:ss format.
5396
 *
5397
 * @author Julian Prud'homme
5398
 *
5399
 * @param int    $seconds      number of seconds
5400
 * @param string $space
5401
 * @param bool   $showSeconds
5402
 * @param bool   $roundMinutes
5403
 *
5404
 * @return string the formatted time
5405
 */
5406
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
5407
{
5408
    // $seconds = -1 means that we have wrong data in the db.
5409
    if ($seconds == -1) {
5410
        return
5411
            get_lang('Unknown').
5412
            Display::return_icon(
5413
                'info2.gif',
5414
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5415
                ['align' => 'absmiddle', 'hspace' => '3px']
5416
            );
5417
    }
5418
5419
    // How many hours ?
5420
    $hours = floor($seconds / 3600);
5421
5422
    // How many minutes ?
5423
    $min = floor(($seconds - ($hours * 3600)) / 60);
5424
5425
    if ($roundMinutes) {
5426
        if ($min >= 45) {
5427
            $min = 45;
5428
        }
5429
5430
        if ($min >= 30 && $min <= 44) {
5431
            $min = 30;
5432
        }
5433
5434
        if ($min >= 15 && $min <= 29) {
5435
            $min = 15;
5436
        }
5437
5438
        if ($min >= 0 && $min <= 14) {
5439
            $min = 0;
5440
        }
5441
    }
5442
5443
    // How many seconds
5444
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5445
5446
    if ($hours < 10) {
5447
        $hours = "0$hours";
5448
    }
5449
5450
    if ($sec < 10) {
5451
        $sec = "0$sec";
5452
    }
5453
5454
    if ($min < 10) {
5455
        $min = "0$min";
5456
    }
5457
5458
    $seconds = '';
5459
    if ($showSeconds) {
5460
        $seconds = $space.$sec;
5461
    }
5462
5463
    return $hours.$space.$min.$seconds;
5464
}
5465
5466
/* FILE SYSTEM RELATED FUNCTIONS */
5467
5468
/**
5469
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5470
 * The return value is based on the platform administrator's setting
5471
 * "Administration > Configuration settings > Security > Permissions for new directories".
5472
 *
5473
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5474
 */
5475
function api_get_permissions_for_new_directories()
5476
{
5477
    static $permissions;
5478
    if (!isset($permissions)) {
5479
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5480
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5481
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5482
    }
5483
5484
    return $permissions;
5485
}
5486
5487
/**
5488
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5489
 * The return value is based on the platform administrator's setting
5490
 * "Administration > Configuration settings > Security > Permissions for new files".
5491
 *
5492
 * @return int returns the permissions in the format
5493
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5494
 */
5495
function api_get_permissions_for_new_files()
5496
{
5497
    static $permissions;
5498
    if (!isset($permissions)) {
5499
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5500
        // The default value 0666 is according to that in the platform
5501
        // administration panel after fresh system installation.
5502
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5503
    }
5504
5505
    return $permissions;
5506
}
5507
5508
/**
5509
 * Deletes a file, or a folder and its contents.
5510
 *
5511
 * @author      Aidan Lister <[email protected]>
5512
 *
5513
 * @version     1.0.3
5514
 *
5515
 * @param string $dirname Directory to delete
5516
 * @param       bool     Deletes only the content or not
5517
 * @param bool $strict if one folder/file fails stop the loop
5518
 *
5519
 * @return bool Returns TRUE on success, FALSE on failure
5520
 *
5521
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5522
 *
5523
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5524
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5525
 */
5526
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5527
{
5528
    $res = true;
5529
    // A sanity check.
5530
    if (!file_exists($dirname)) {
5531
        return false;
5532
    }
5533
    $php_errormsg = '';
5534
    // Simple delete for a file.
5535
    if (is_file($dirname) || is_link($dirname)) {
5536
        $res = unlink($dirname);
5537
        if ($res === false) {
5538
            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);
5539
        }
5540
5541
        return $res;
5542
    }
5543
5544
    // Loop through the folder.
5545
    $dir = dir($dirname);
5546
    // A sanity check.
5547
    $is_object_dir = is_object($dir);
5548
    if ($is_object_dir) {
5549
        while (false !== $entry = $dir->read()) {
5550
            // Skip pointers.
5551
            if ($entry == '.' || $entry == '..') {
5552
                continue;
5553
            }
5554
5555
            // Recurse.
5556
            if ($strict) {
5557
                $result = rmdirr("$dirname/$entry");
5558
                if ($result == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
5559
                    $res = false;
5560
                    break;
5561
                }
5562
            } else {
5563
                rmdirr("$dirname/$entry");
5564
            }
5565
        }
5566
    }
5567
5568
    // Clean up.
5569
    if ($is_object_dir) {
5570
        $dir->close();
5571
    }
5572
5573
    if ($delete_only_content_in_folder == false) {
5574
        $res = rmdir($dirname);
5575
        if ($res === false) {
5576
            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);
5577
        }
5578
    }
5579
5580
    return $res;
5581
}
5582
5583
// TODO: This function is to be simplified. File access modes to be implemented.
5584
/**
5585
 * function adapted from a php.net comment
5586
 * copy recursively a folder.
5587
 *
5588
 * @param string $source       the source folder
5589
 * @param string $dest         the dest folder
5590
 * @param array  $exclude      an array of excluded file_name (without extension)
5591
 * @param array  $copied_files the returned array of copied files
5592
 */
5593
function copyr($source, $dest, $exclude = [], $copied_files = [])
5594
{
5595
    if (empty($dest)) {
5596
        return false;
5597
    }
5598
    // Simple copy for a file
5599
    if (is_file($source)) {
5600
        $path_info = pathinfo($source);
5601
        if (!in_array($path_info['filename'], $exclude)) {
5602
            copy($source, $dest);
5603
        }
5604
5605
        return true;
5606
    } elseif (!is_dir($source)) {
5607
        //then source is not a dir nor a file, return
5608
        return false;
5609
    }
5610
5611
    // Make destination directory.
5612
    if (!is_dir($dest)) {
5613
        mkdir($dest, api_get_permissions_for_new_directories());
5614
    }
5615
5616
    // Loop through the folder.
5617
    $dir = dir($source);
5618
    while (false !== $entry = $dir->read()) {
5619
        // Skip pointers
5620
        if ($entry == '.' || $entry == '..') {
5621
            continue;
5622
        }
5623
5624
        // Deep copy directories.
5625
        if ($dest !== "$source/$entry") {
5626
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
5627
        }
5628
    }
5629
    // Clean up.
5630
    $dir->close();
5631
5632
    return true;
5633
}
5634
5635
/**
5636
 * @param string $pathname
5637
 * @param string $base_path_document
5638
 * @param int    $session_id
5639
 * @param array
5640
 * @param string
5641
 *
5642
 * @return mixed True if directory already exists, false if a file already exists at
5643
 *               the destination and null if everything goes according to plan
5644
 *@todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5645
 * Documentation header to be added here.
5646
 */
5647
function copy_folder_course_session(
5648
    $pathname,
5649
    $base_path_document,
5650
    $session_id,
5651
    $course_info,
5652
    $document,
5653
    $source_course_id,
5654
    $originalFolderNameList = [],
5655
    $originalBaseName = ''
5656
) {
5657
    // Check whether directory already exists.
5658
    if (empty($pathname) || is_dir($pathname)) {
5659
        return true;
5660
    }
5661
5662
    // Ensure that a file with the same name does not already exist.
5663
    if (is_file($pathname)) {
5664
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5665
5666
        return false;
5667
    }
5668
5669
    //error_log('checking:');
5670
    //error_log(str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5671
    $baseNoDocument = str_replace('document', '', $originalBaseName);
5672
    $folderTitles = explode('/', $baseNoDocument);
5673
    $folderTitles = array_filter($folderTitles);
5674
5675
    //error_log($baseNoDocument);error_log(print_r($folderTitles, 1));
5676
5677
    $table = Database::get_course_table(TABLE_DOCUMENT);
5678
    $session_id = (int) $session_id;
5679
    $source_course_id = (int) $source_course_id;
5680
    $course_id = $course_info['real_id'];
5681
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5682
    $new_pathname = $base_path_document;
5683
5684
    $path = '';
5685
    foreach ($folders as $index => $folder) {
5686
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5687
        $path .= DIRECTORY_SEPARATOR.$folder;
5688
5689
        if (!file_exists($new_pathname)) {
5690
            $path = Database::escape_string($path);
5691
            //error_log("path: $path");
5692
            $sql = "SELECT * FROM $table
5693
                    WHERE
5694
                        c_id = $source_course_id AND
5695
                        path = '$path' AND
5696
                        filetype = 'folder' AND
5697
                        session_id = '$session_id'";
5698
            $rs1 = Database::query($sql);
5699
            $num_rows = Database::num_rows($rs1);
5700
5701
            if (0 == $num_rows) {
5702
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5703
                $title = basename($new_pathname);
5704
5705
                if (isset($folderTitles[$index + 1])) {
5706
                    $checkPath = $folderTitles[$index + 1];
5707
                    //error_log("check $checkPath");
5708
                    if (isset($originalFolderNameList[$checkPath])) {
5709
                        $title = $originalFolderNameList[$checkPath];
5710
                        //error_log('use this name: '.$title);
5711
                    }
5712
                }
5713
5714
                // Insert new folder with destination session_id.
5715
                $params = [
5716
                    'c_id' => $course_id,
5717
                    'path' => $path,
5718
                    'comment' => $document->comment,
5719
                    'title' => $title,
5720
                    'filetype' => 'folder',
5721
                    'size' => '0',
5722
                    'session_id' => $session_id,
5723
                ];
5724
5725
                //error_log("old $folder"); error_log("Add doc $title in $path");
5726
                $document_id = Database::insert($table, $params);
5727
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5728
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5729
                    Database::query($sql);
5730
5731
                    api_item_property_update(
5732
                        $course_info,
5733
                        TOOL_DOCUMENT,
5734
                        $document_id,
5735
                        'FolderCreated',
5736
                        api_get_user_id(),
5737
                        0,
5738
                        0,
5739
                        null,
5740
                        null,
5741
                        $session_id
5742
                    );
5743
                }
5744
            }
5745
        }
5746
    }
5747
}
5748
5749
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5750
/**
5751
 * @param string $path
5752
 */
5753
function api_chmod_R($path, $filemode)
5754
{
5755
    if (!is_dir($path)) {
5756
        return chmod($path, $filemode);
5757
    }
5758
5759
    $handler = opendir($path);
5760
    while ($file = readdir($handler)) {
5761
        if ($file != '.' && $file != '..') {
5762
            $fullpath = "$path/$file";
5763
            if (!is_dir($fullpath)) {
5764
                if (!chmod($fullpath, $filemode)) {
5765
                    return false;
5766
                }
5767
            } else {
5768
                if (!api_chmod_R($fullpath, $filemode)) {
5769
                    return false;
5770
                }
5771
            }
5772
        }
5773
    }
5774
5775
    closedir($handler);
5776
5777
    return chmod($path, $filemode);
5778
}
5779
5780
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5781
/**
5782
 * Parse info file format. (e.g: file.info).
5783
 *
5784
 * Files should use an ini-like format to specify values.
5785
 * White-space generally doesn't matter, except inside values.
5786
 * e.g.
5787
 *
5788
 * @verbatim
5789
 *   key = value
5790
 *   key = "value"
5791
 *   key = 'value'
5792
 *   key = "multi-line
5793
 *
5794
 *   value"
5795
 *   key = 'multi-line
5796
 *
5797
 *   value'
5798
 *   key
5799
 *   =
5800
 *   'value'
5801
 * @endverbatim
5802
 *
5803
 * Arrays are created using a GET-like syntax:
5804
 *
5805
 * @verbatim
5806
 *   key[] = "numeric array"
5807
 *   key[index] = "associative array"
5808
 *   key[index][] = "nested numeric array"
5809
 *   key[index][index] = "nested associative array"
5810
 * @endverbatim
5811
 *
5812
 * PHP constants are substituted in, but only when used as the entire value:
5813
 *
5814
 * Comments should start with a semi-colon at the beginning of a line.
5815
 *
5816
 * This function is NOT for placing arbitrary module-specific settings. Use
5817
 * variable_get() and variable_set() for that.
5818
 *
5819
 * Information stored in the module.info file:
5820
 * - name: The real name of the module for display purposes.
5821
 * - description: A brief description of the module.
5822
 * - dependencies: An array of shortnames of other modules this module depends on.
5823
 * - package: The name of the package of modules this module belongs to.
5824
 *
5825
 * Example of .info file:
5826
 * <code>
5827
 * @verbatim
5828
 *   name = Forum
5829
 *   description = Enables threaded discussions about general topics.
5830
 *   dependencies[] = taxonomy
5831
 *   dependencies[] = comment
5832
 *   package = Core - optional
5833
 *   version = VERSION
5834
 * @endverbatim
5835
 * </code>
5836
 *
5837
 * @param string $filename
5838
 *                         The file we are parsing. Accepts file with relative or absolute path.
5839
 *
5840
 * @return
5841
 *   The info array
5842
 */
5843
function api_parse_info_file($filename)
5844
{
5845
    $info = [];
5846
5847
    if (!file_exists($filename)) {
5848
        return $info;
5849
    }
5850
5851
    $data = file_get_contents($filename);
5852
    if (preg_match_all('
5853
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5854
        ((?:
5855
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5856
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5857
        )+?)
5858
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5859
        (?:
5860
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5861
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5862
          ([^\r\n]*?)                   # Non-quoted string
5863
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5864
        @msx', $data, $matches, PREG_SET_ORDER)) {
5865
        $key = $value1 = $value2 = $value3 = '';
5866
        foreach ($matches as $match) {
5867
            // Fetch the key and value string.
5868
            $i = 0;
5869
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5870
                $$var = isset($match[++$i]) ? $match[$i] : '';
5871
            }
5872
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5873
5874
            // Parse array syntax.
5875
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5876
            $last = array_pop($keys);
5877
            $parent = &$info;
5878
5879
            // Create nested arrays.
5880
            foreach ($keys as $key) {
5881
                if ($key == '') {
5882
                    $key = count($parent);
5883
                }
5884
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5885
                    $parent[$key] = [];
5886
                }
5887
                $parent = &$parent[$key];
5888
            }
5889
5890
            // Handle PHP constants.
5891
            if (defined($value)) {
5892
                $value = constant($value);
5893
            }
5894
5895
            // Insert actual value.
5896
            if ($last == '') {
5897
                $last = count($parent);
5898
            }
5899
            $parent[$last] = $value;
5900
        }
5901
    }
5902
5903
    return $info;
5904
}
5905
5906
/**
5907
 * Gets Chamilo version from the configuration files.
5908
 *
5909
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5910
 */
5911
function api_get_version()
5912
{
5913
    return (string) api_get_configuration_value('system_version');
5914
}
5915
5916
/**
5917
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5918
 *
5919
 * @return string
5920
 */
5921
function api_get_software_name()
5922
{
5923
    $name = api_get_configuration_value('software_name');
5924
    if (!empty($name)) {
5925
        return $name;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $name also could return the type boolean which is incompatible with the documented return type string.
Loading history...
5926
    } else {
5927
        return 'Chamilo';
5928
    }
5929
}
5930
5931
/**
5932
 * Checks whether status given in parameter exists in the platform.
5933
 *
5934
 * @param mixed the status (can be either int either string)
5935
 *
5936
 * @return bool if the status exists, else returns false
5937
 */
5938
function api_status_exists($status_asked)
5939
{
5940
    global $_status_list;
5941
5942
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5943
}
5944
5945
/**
5946
 * Checks whether status given in parameter exists in the platform. The function
5947
 * returns the status ID or false if it does not exist, but given the fact there
5948
 * is no "0" status, the return value can be checked against
5949
 * if(api_status_key()) to know if it exists.
5950
 *
5951
 * @param   mixed   The status (can be either int or string)
5952
 *
5953
 * @return mixed Status ID if exists, false otherwise
5954
 */
5955
function api_status_key($status)
5956
{
5957
    global $_status_list;
5958
5959
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5960
}
5961
5962
/**
5963
 * Gets the status langvars list.
5964
 *
5965
 * @return string[] the list of status with their translations
5966
 */
5967
function api_get_status_langvars()
5968
{
5969
    return [
5970
        COURSEMANAGER => get_lang('Teacher', ''),
5971
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5972
        DRH => get_lang('Drh', ''),
5973
        STUDENT => get_lang('Student', ''),
5974
        ANONYMOUS => get_lang('Anonymous', ''),
5975
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5976
        INVITEE => get_lang('Invited'),
5977
    ];
5978
}
5979
5980
/**
5981
 * The function that retrieves all the possible settings for a certain config setting.
5982
 *
5983
 * @author Patrick Cool <[email protected]>, Ghent University
5984
 */
5985
function api_get_settings_options($var)
5986
{
5987
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5988
    $var = Database::escape_string($var);
5989
    $sql = "SELECT * FROM $table_settings_options
5990
            WHERE variable = '$var'
5991
            ORDER BY id";
5992
    $result = Database::query($sql);
5993
    $settings_options_array = [];
5994
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5995
        $settings_options_array[] = $row;
5996
    }
5997
5998
    return $settings_options_array;
5999
}
6000
6001
/**
6002
 * @param array $params
6003
 */
6004
function api_set_setting_option($params)
6005
{
6006
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6007
    if (empty($params['id'])) {
6008
        Database::insert($table, $params);
6009
    } else {
6010
        Database::update($table, $params, ['id = ? ' => $params['id']]);
6011
    }
6012
}
6013
6014
/**
6015
 * @param array $params
6016
 */
6017
function api_set_setting_simple($params)
6018
{
6019
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6020
    $url_id = api_get_current_access_url_id();
6021
6022
    if (empty($params['id'])) {
6023
        $params['access_url'] = $url_id;
6024
        Database::insert($table, $params);
6025
    } else {
6026
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
6027
    }
6028
}
6029
6030
/**
6031
 * @param int $id
6032
 */
6033
function api_delete_setting_option($id)
6034
{
6035
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6036
    if (!empty($id)) {
6037
        Database::delete($table, ['id = ? ' => $id]);
6038
    }
6039
}
6040
6041
/**
6042
 * Sets a platform configuration setting to a given value.
6043
 *
6044
 * @param string    The variable we want to update
6045
 * @param string    The value we want to record
6046
 * @param string    The sub-variable if any (in most cases, this will remain null)
6047
 * @param string    The category if any (in most cases, this will remain null)
6048
 * @param int       The access_url for which this parameter is valid
6049
 * @param string $cat
6050
 *
6051
 * @return bool|null
6052
 */
6053
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
6054
{
6055
    if (empty($var)) {
6056
        return false;
6057
    }
6058
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6059
    $var = Database::escape_string($var);
6060
    $value = Database::escape_string($value);
6061
    $access_url = (int) $access_url;
6062
    if (empty($access_url)) {
6063
        $access_url = 1;
6064
    }
6065
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
6066
    if (!empty($subvar)) {
6067
        $subvar = Database::escape_string($subvar);
6068
        $select .= " AND subkey = '$subvar'";
6069
    }
6070
    if (!empty($cat)) {
6071
        $cat = Database::escape_string($cat);
6072
        $select .= " AND category = '$cat'";
6073
    }
6074
    if ($access_url > 1) {
6075
        $select .= " AND access_url = $access_url";
6076
    } else {
6077
        $select .= " AND access_url = 1 ";
6078
    }
6079
6080
    $res = Database::query($select);
6081
    if (Database::num_rows($res) > 0) {
6082
        // Found item for this access_url.
6083
        $row = Database::fetch_array($res);
6084
        $sql = "UPDATE $t_settings SET selected_value = '$value'
6085
                WHERE id = ".$row['id'];
6086
        Database::query($sql);
6087
    } else {
6088
        // Item not found for this access_url, we have to check if it exist with access_url = 1
6089
        $select = "SELECT * FROM $t_settings
6090
                   WHERE variable = '$var' AND access_url = 1 ";
6091
        // Just in case
6092
        if ($access_url == 1) {
6093
            if (!empty($subvar)) {
6094
                $select .= " AND subkey = '$subvar'";
6095
            }
6096
            if (!empty($cat)) {
6097
                $select .= " AND category = '$cat'";
6098
            }
6099
            $res = Database::query($select);
6100
            if (Database::num_rows($res) > 0) {
6101
                // We have a setting for access_url 1, but none for the current one, so create one.
6102
                $row = Database::fetch_array($res);
6103
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
6104
                        VALUES
6105
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6106
                        "'".$row['type']."','".$row['category']."',".
6107
                        "'$value','".$row['title']."',".
6108
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6109
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
6110
                Database::query($insert);
6111
            } else {
6112
                // Such a setting does not exist.
6113
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
6114
            }
6115
        } else {
6116
            // Other access url.
6117
            if (!empty($subvar)) {
6118
                $select .= " AND subkey = '$subvar'";
6119
            }
6120
            if (!empty($cat)) {
6121
                $select .= " AND category = '$cat'";
6122
            }
6123
            $res = Database::query($select);
6124
6125
            if (Database::num_rows($res) > 0) {
6126
                // We have a setting for access_url 1, but none for the current one, so create one.
6127
                $row = Database::fetch_array($res);
6128
                if ($row['access_url_changeable'] == 1) {
6129
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
6130
                            ('".$row['variable']."',".
6131
                            (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6132
                            "'".$row['type']."','".$row['category']."',".
6133
                            "'$value','".$row['title']."',".
6134
                            "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
6135
                            (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6136
                            "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
6137
                    Database::query($insert);
6138
                }
6139
            } else { // Such a setting does not exist.
6140
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
6141
            }
6142
        }
6143
    }
6144
}
6145
6146
/**
6147
 * Sets a whole category of settings to one specific value.
6148
 *
6149
 * @param string    Category
6150
 * @param string    Value
6151
 * @param int       Access URL. Optional. Defaults to 1
6152
 * @param array     Optional array of filters on field type
6153
 * @param string $category
6154
 * @param string $value
6155
 *
6156
 * @return bool
6157
 */
6158
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
6159
{
6160
    if (empty($category)) {
6161
        return false;
6162
    }
6163
    $category = Database::escape_string($category);
6164
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6165
    $access_url = (int) $access_url;
6166
    if (empty($access_url)) {
6167
        $access_url = 1;
6168
    }
6169
    if (isset($value)) {
6170
        $value = Database::escape_string($value);
6171
        $sql = "UPDATE $t_s SET selected_value = '$value'
6172
                WHERE category = '$category' AND access_url = $access_url";
6173
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6174
            $sql .= " AND ( ";
6175
            $i = 0;
6176
            foreach ($fieldtype as $type) {
6177
                if ($i > 0) {
6178
                    $sql .= ' OR ';
6179
                }
6180
                $type = Database::escape_string($type);
6181
                $sql .= " type='".$type."' ";
6182
                $i++;
6183
            }
6184
            $sql .= ")";
6185
        }
6186
        $res = Database::query($sql);
6187
6188
        return $res !== false;
6189
    } else {
6190
        $sql = "UPDATE $t_s SET selected_value = NULL
6191
                WHERE category = '$category' AND access_url = $access_url";
6192
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6193
            $sql .= " AND ( ";
6194
            $i = 0;
6195
            foreach ($fieldtype as $type) {
6196
                if ($i > 0) {
6197
                    $sql .= ' OR ';
6198
                }
6199
                $type = Database::escape_string($type);
6200
                $sql .= " type='".$type."' ";
6201
                $i++;
6202
            }
6203
            $sql .= ")";
6204
        }
6205
        $res = Database::query($sql);
6206
6207
        return $res !== false;
6208
    }
6209
}
6210
6211
/**
6212
 * Gets all available access urls in an array (as in the database).
6213
 *
6214
 * @return array An array of database records
6215
 */
6216
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
6217
{
6218
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6219
    $from = (int) $from;
6220
    $to = (int) $to;
6221
    $order = Database::escape_string($order, null, false);
6222
    $direction = Database::escape_string($direction, null, false);
6223
    $sql = "SELECT id, url, description, active, created_by, tms
6224
            FROM $table
6225
            ORDER BY $order $direction
6226
            LIMIT $to OFFSET $from";
6227
    $res = Database::query($sql);
6228
6229
    return Database::store_result($res);
6230
}
6231
6232
/**
6233
 * Gets the access url info in an array.
6234
 *
6235
 * @param int  $id            Id of the access url
6236
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
6237
 *
6238
 * @return array All the info (url, description, active, created_by, tms)
6239
 *               from the access_url table
6240
 *
6241
 * @author Julio Montoya
6242
 */
6243
function api_get_access_url($id, $returnDefault = true)
6244
{
6245
    static $staticResult;
6246
    $id = (int) $id;
6247
6248
    if (isset($staticResult[$id])) {
6249
        $result = $staticResult[$id];
6250
    } else {
6251
        // Calling the Database:: library dont work this is handmade.
6252
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6253
        $sql = "SELECT url, description, active, created_by, tms
6254
                FROM $table_access_url WHERE id = '$id' ";
6255
        $res = Database::query($sql);
6256
        $result = @Database::fetch_array($res);
6257
        $staticResult[$id] = $result;
6258
    }
6259
6260
    // If the result url is 'http://localhost/' (the default) and the root_web
6261
    // (=current url) is different, and the $id is = 1 (which might mean
6262
    // api_get_current_access_url_id() returned 1 by default), then return the
6263
    // root_web setting instead of the current URL
6264
    // This is provided as an option to avoid breaking the storage of URL-specific
6265
    // homepages in home/localhost/
6266
    if ($id === 1 && $returnDefault === false) {
6267
        $currentUrl = api_get_current_access_url_id();
6268
        // only do this if we are on the main URL (=1), otherwise we could get
6269
        // information on another URL instead of the one asked as parameter
6270
        if ($currentUrl === 1) {
6271
            $rootWeb = api_get_path(WEB_PATH);
6272
            $default = 'http://localhost/';
6273
            if ($result['url'] === $default && $rootWeb != $default) {
6274
                $result['url'] = $rootWeb;
6275
            }
6276
        }
6277
    }
6278
6279
    return $result;
6280
}
6281
6282
/**
6283
 * Gets all the current settings for a specific access url.
6284
 *
6285
 * @param string    The category, if any, that we want to get
6286
 * @param string    Whether we want a simple list (display a category) or
6287
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
6288
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
6289
 *
6290
 * @return array Array of database results for the current settings of the current access URL
6291
 */
6292
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
6293
{
6294
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6295
    $access_url = (int) $access_url;
6296
    $where_condition = '';
6297
    if ($url_changeable == 1) {
6298
        $where_condition = " AND access_url_changeable= '1' ";
6299
    }
6300
    if (empty($access_url) || $access_url == -1) {
6301
        $access_url = 1;
6302
    }
6303
    $sql = "SELECT * FROM $table
6304
            WHERE access_url = $access_url  $where_condition ";
6305
6306
    if (!empty($cat)) {
6307
        $cat = Database::escape_string($cat);
6308
        $sql .= " AND category='$cat' ";
6309
    }
6310
    if ($ordering == 'group') {
6311
        $sql .= " ORDER BY id ASC";
6312
    } else {
6313
        $sql .= " ORDER BY 1,2 ASC";
6314
    }
6315
    $result = Database::query($sql);
6316
    if ($result === null) {
6317
        return [];
6318
    }
6319
    $result = Database::store_result($result, 'ASSOC');
6320
6321
    return $result;
6322
}
6323
6324
/**
6325
 * @param string $value       The value we want to record
6326
 * @param string $variable    The variable name we want to insert
6327
 * @param string $subKey      The subkey for the variable we want to insert
6328
 * @param string $type        The type for the variable we want to insert
6329
 * @param string $category    The category for the variable we want to insert
6330
 * @param string $title       The title
6331
 * @param string $comment     The comment
6332
 * @param string $scope       The scope
6333
 * @param string $subKeyText  The subkey text
6334
 * @param int    $accessUrlId The access_url for which this parameter is valid
6335
 * @param int    $visibility  The changeability of this setting for non-master urls
6336
 *
6337
 * @return int The setting ID
6338
 */
6339
function api_add_setting(
6340
    $value,
6341
    $variable,
6342
    $subKey = '',
6343
    $type = 'textfield',
6344
    $category = '',
6345
    $title = '',
6346
    $comment = '',
6347
    $scope = '',
6348
    $subKeyText = '',
6349
    $accessUrlId = 1,
6350
    $visibility = 0
6351
) {
6352
    $em = Database::getManager();
6353
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6354
    $accessUrlId = (int) $accessUrlId ?: 1;
6355
6356
    if (is_array($value)) {
6357
        $value = serialize($value);
6358
    } else {
6359
        $value = trim($value);
6360
    }
6361
6362
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
6363
6364
    if (!empty($subKey)) {
6365
        $criteria['subkey'] = $subKey;
6366
    }
6367
6368
    // Check if this variable doesn't exist already
6369
    /** @var SettingsCurrent $setting */
6370
    $setting = $settingRepo->findOneBy($criteria);
6371
6372
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
6373
        $setting->setSelectedValue($value);
6374
6375
        $em->persist($setting);
6376
        $em->flush();
6377
6378
        return $setting->getId();
6379
    }
6380
6381
    // Item not found for this access_url, we have to check if the whole thing is missing
6382
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6383
    $setting = new SettingsCurrent();
6384
    $setting
6385
        ->setVariable($variable)
6386
        ->setSelectedValue($value)
6387
        ->setType($type)
6388
        ->setCategory($category)
6389
        ->setSubkey($subKey)
6390
        ->setTitle($title)
6391
        ->setComment($comment)
6392
        ->setScope($scope)
6393
        ->setSubkeytext($subKeyText)
6394
        ->setAccessUrl($accessUrlId)
6395
        ->setAccessUrlChangeable($visibility);
6396
6397
    $em->persist($setting);
6398
    $em->flush();
6399
6400
    return $setting->getId();
6401
}
6402
6403
/**
6404
 * Checks wether a user can or can't view the contents of a course.
6405
 *
6406
 * @deprecated use CourseManager::is_user_subscribed_in_course
6407
 *
6408
 * @param int $userid User id or NULL to get it from $_SESSION
6409
 * @param int $cid    course id to check whether the user is allowed
6410
 *
6411
 * @return bool
6412
 */
6413
function api_is_course_visible_for_user($userid = null, $cid = null)
6414
{
6415
    if ($userid === null) {
6416
        $userid = api_get_user_id();
6417
    }
6418
    if (empty($userid) || strval(intval($userid)) != $userid) {
6419
        if (api_is_anonymous()) {
6420
            $userid = api_get_anonymous_id();
6421
        } else {
6422
            return false;
6423
        }
6424
    }
6425
    $cid = Database::escape_string($cid);
6426
6427
    $courseInfo = api_get_course_info($cid);
6428
    $courseId = $courseInfo['real_id'];
6429
    $is_platformAdmin = api_is_platform_admin();
6430
6431
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6432
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6433
6434
    $sql = "SELECT
6435
                $course_table.category_code,
6436
                $course_table.visibility,
6437
                $course_table.code,
6438
                $course_cat_table.code
6439
            FROM $course_table
6440
            LEFT JOIN $course_cat_table
6441
                ON $course_table.category_code = $course_cat_table.code
6442
            WHERE
6443
                $course_table.code = '$cid'
6444
            LIMIT 1";
6445
6446
    $result = Database::query($sql);
6447
6448
    if (Database::num_rows($result) > 0) {
6449
        $visibility = Database::fetch_array($result);
6450
        $visibility = $visibility['visibility'];
6451
    } else {
6452
        $visibility = 0;
6453
    }
6454
    // Shortcut permissions in case the visibility is "open to the world".
6455
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
6456
        return true;
6457
    }
6458
6459
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6460
6461
    $sql = "SELECT
6462
                is_tutor, status
6463
            FROM $tbl_course_user
6464
            WHERE
6465
                user_id  = '$userid' AND
6466
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6467
                c_id = $courseId
6468
            LIMIT 1";
6469
6470
    $result = Database::query($sql);
6471
6472
    if (Database::num_rows($result) > 0) {
6473
        // This user has got a recorded state for this course.
6474
        $cuData = Database::fetch_array($result);
6475
        $is_courseMember = true;
6476
        $is_courseAdmin = ($cuData['status'] == 1);
6477
    }
6478
6479
    if (!$is_courseAdmin) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $is_courseAdmin does not seem to be defined for all execution paths leading up to this point.
Loading history...
6480
        // This user has no status related to this course.
6481
        // Is it the session coach or the session admin?
6482
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6483
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6484
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6485
6486
        $sql = "SELECT
6487
                    session.id_coach, session_admin_id, session.id
6488
                FROM
6489
                    $tbl_session as session
6490
                INNER JOIN $tbl_session_course
6491
                    ON session_rel_course.session_id = session.id
6492
                    AND session_rel_course.c_id = '$courseId'
6493
                LIMIT 1";
6494
6495
        $result = Database::query($sql);
6496
        $row = Database::store_result($result);
6497
6498
        if ($row[0]['id_coach'] == $userid) {
6499
            $is_courseMember = true;
6500
            $is_courseAdmin = false;
6501
        } elseif ($row[0]['session_admin_id'] == $userid) {
6502
            $is_courseMember = false;
6503
            $is_courseAdmin = false;
6504
        } else {
6505
            // Check if the current user is the course coach.
6506
            $sql = "SELECT 1
6507
                    FROM $tbl_session_course
6508
                    WHERE session_rel_course.c_id = '$courseId'
6509
                    AND session_rel_course.id_coach = '$userid'
6510
                    LIMIT 1";
6511
6512
            $result = Database::query($sql);
6513
6514
            //if ($row = Database::fetch_array($result)) {
6515
            if (Database::num_rows($result) > 0) {
6516
                $is_courseMember = true;
6517
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6518
6519
                $sql = "SELECT status FROM $tbl_user
6520
                        WHERE user_id = $userid
6521
                        LIMIT 1";
6522
6523
                $result = Database::query($sql);
6524
6525
                if (Database::result($result, 0, 0) == 1) {
6526
                    $is_courseAdmin = true;
6527
                } else {
6528
                    $is_courseAdmin = false;
6529
                }
6530
            } else {
6531
                // Check if the user is a student is this session.
6532
                $sql = "SELECT  id
6533
                        FROM $tbl_session_course_user
6534
                        WHERE
6535
                            user_id  = '$userid' AND
6536
                            c_id = '$courseId'
6537
                        LIMIT 1";
6538
6539
                if (Database::num_rows($result) > 0) {
6540
                    // This user haa got a recorded state for this course.
6541
                    while ($row = Database::fetch_array($result)) {
6542
                        $is_courseMember = true;
6543
                        $is_courseAdmin = false;
6544
                    }
6545
                }
6546
            }
6547
        }
6548
    }
6549
6550
    switch ($visibility) {
6551
        case COURSE_VISIBILITY_OPEN_WORLD:
6552
            return true;
6553
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6554
            return isset($userid);
6555
        case COURSE_VISIBILITY_REGISTERED:
6556
        case COURSE_VISIBILITY_CLOSED:
6557
            return $is_platformAdmin || $is_courseMember || $is_courseAdmin;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $is_courseMember does not seem to be defined for all execution paths leading up to this point.
Loading history...
6558
        case COURSE_VISIBILITY_HIDDEN:
6559
            return $is_platformAdmin;
6560
    }
6561
6562
    return false;
6563
}
6564
6565
/**
6566
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6567
 *
6568
 * @param string the tool of the element
6569
 * @param int the element id in database
6570
 * @param int the session_id to compare with element session id
6571
 *
6572
 * @return bool true if the element is in the session, false else
6573
 */
6574
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6575
{
6576
    if (is_null($session_id)) {
6577
        $session_id = api_get_session_id();
6578
    }
6579
6580
    $element_id = (int) $element_id;
6581
6582
    if (empty($element_id)) {
6583
        return false;
6584
    }
6585
6586
    // Get information to build query depending of the tool.
6587
    switch ($tool) {
6588
        case TOOL_SURVEY:
6589
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6590
            $key_field = 'survey_id';
6591
            break;
6592
        case TOOL_ANNOUNCEMENT:
6593
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6594
            $key_field = 'id';
6595
            break;
6596
        case TOOL_AGENDA:
6597
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6598
            $key_field = 'id';
6599
            break;
6600
        case TOOL_GROUP:
6601
            $table_tool = Database::get_course_table(TABLE_GROUP);
6602
            $key_field = 'id';
6603
            break;
6604
        default:
6605
            return false;
6606
    }
6607
    $course_id = api_get_course_int_id();
6608
6609
    $sql = "SELECT session_id FROM $table_tool
6610
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6611
    $rs = Database::query($sql);
6612
    if ($element_session_id = Database::result($rs, 0, 0)) {
6613
        if ($element_session_id == intval($session_id)) {
6614
            // The element belongs to the session.
6615
            return true;
6616
        }
6617
    }
6618
6619
    return false;
6620
}
6621
6622
/**
6623
 * Replaces "forbidden" characters in a filename string.
6624
 *
6625
 * @param string $filename
6626
 * @param bool   $treat_spaces_as_hyphens
6627
 *
6628
 * @return string
6629
 */
6630
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6631
{
6632
    // Some non-properly encoded file names can cause the whole file to be
6633
    // skipped when uploaded. Avoid this by detecting the encoding and
6634
    // converting to UTF-8, setting the source as ASCII (a reasonably
6635
    // limited characters set) if nothing could be found (BT#
6636
    $encoding = api_detect_encoding($filename);
6637
    if (empty($encoding)) {
6638
        $encoding = 'ASCII';
6639
        if (!api_is_valid_ascii($filename)) {
6640
            // try iconv and try non standard ASCII a.k.a CP437
6641
            // see BT#15022
6642
            if (function_exists('iconv')) {
6643
                $result = iconv('CP437', 'UTF-8', $filename);
6644
                if (api_is_valid_utf8($result)) {
6645
                    $filename = $result;
6646
                    $encoding = 'UTF-8';
6647
                }
6648
            }
6649
        }
6650
    }
6651
6652
    $filename = api_to_system_encoding($filename, $encoding);
6653
6654
    $url = URLify::filter(
6655
        $filename,
6656
        250,
6657
        '',
6658
        true,
6659
        false,
6660
        false,
6661
        false,
6662
        $treat_spaces_as_hyphens
6663
    );
6664
6665
    return $url;
6666
}
6667
6668
/**
6669
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6670
 *
6671
 * @author Ivan Tcholakov, 28-JUN-2006.
6672
 */
6673
function api_request_uri()
6674
{
6675
    if (!empty($_SERVER['REQUEST_URI'])) {
6676
        return $_SERVER['REQUEST_URI'];
6677
    }
6678
    $uri = $_SERVER['SCRIPT_NAME'];
6679
    if (!empty($_SERVER['QUERY_STRING'])) {
6680
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6681
    }
6682
    $_SERVER['REQUEST_URI'] = $uri;
6683
6684
    return $uri;
6685
}
6686
6687
/**
6688
 * Gets the current access_url id of the Chamilo Platform.
6689
 *
6690
 * @return int access_url_id of the current Chamilo Installation or 1 if multiple_access_urls is not enabled
6691
 *
6692
 * @author Julio Montoya <[email protected]>
6693
 */
6694
function api_get_current_access_url_id()
6695
{
6696
    if ('cli' === PHP_SAPI) {
6697
        $accessUrlId = api_get_configuration_value('access_url');
6698
        if (!empty($accessUrlId)) {
6699
            return $accessUrlId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $accessUrlId also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
6700
        }
6701
    }
6702
6703
    static $id;
6704
    if (!empty($id)) {
6705
        return (int) $id;
6706
    }
6707
6708
    if (!api_get_multiple_access_url()) {
6709
        // If the feature is not enabled, assume 1 and return before querying
6710
        // the database
6711
        return 1;
6712
    }
6713
6714
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6715
    $path = Database::escape_string(api_get_path(WEB_PATH));
6716
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6717
    $result = Database::query($sql);
6718
    if (Database::num_rows($result) > 0) {
6719
        $id = Database::result($result, 0, 0);
6720
        if ($id === false) {
6721
            return -1;
6722
        }
6723
6724
        return (int) $id;
6725
    }
6726
6727
    $id = 1;
6728
6729
    //if the url in WEB_PATH was not found, it can only mean that there is
6730
    // either a configuration problem or the first URL has not been defined yet
6731
    // (by default it is http://localhost/). Thus the more sensible thing we can
6732
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6733
    return 1;
6734
}
6735
6736
/**
6737
 * Gets the registered urls from a given user id.
6738
 *
6739
 * @param int $user_id
6740
 *
6741
 * @return array
6742
 *
6743
 * @author Julio Montoya <[email protected]>
6744
 */
6745
function api_get_access_url_from_user($user_id)
6746
{
6747
    $user_id = (int) $user_id;
6748
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6749
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6750
    $sql = "SELECT access_url_id
6751
            FROM $table_url_rel_user url_rel_user
6752
            INNER JOIN $table_url u
6753
            ON (url_rel_user.access_url_id = u.id)
6754
            WHERE user_id = ".intval($user_id);
6755
    $result = Database::query($sql);
6756
    $list = [];
6757
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6758
        $list[] = $row['access_url_id'];
6759
    }
6760
6761
    return $list;
6762
}
6763
6764
/**
6765
 * Gets the status of a user in a course.
6766
 *
6767
 * @param int $user_id
6768
 * @param int $courseId
6769
 *
6770
 * @return int user status
6771
 */
6772
function api_get_status_of_user_in_course($user_id, $courseId)
6773
{
6774
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6775
    if (!empty($user_id) && !empty($courseId)) {
6776
        $user_id = intval($user_id);
6777
        $courseId = intval($courseId);
6778
        $sql = 'SELECT status
6779
                FROM '.$tbl_rel_course_user.'
6780
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6781
        $result = Database::query($sql);
6782
        $row_status = Database::fetch_array($result, 'ASSOC');
6783
6784
        return $row_status['status'];
6785
    } else {
6786
        return 0;
6787
    }
6788
}
6789
6790
/**
6791
 * Checks whether the curent user is in a group or not.
6792
 *
6793
 * @param string        The group id - optional (takes it from session if not given)
6794
 * @param string        The course code - optional (no additional check by course if course code is not given)
6795
 *
6796
 * @return bool
6797
 *
6798
 * @author Ivan Tcholakov
6799
 */
6800
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6801
{
6802
    if (!empty($courseCodeParam)) {
6803
        $courseCode = api_get_course_id();
6804
        if (!empty($courseCode)) {
6805
            if ($courseCodeParam != $courseCode) {
6806
                return false;
6807
            }
6808
        } else {
6809
            return false;
6810
        }
6811
    }
6812
6813
    $groupId = api_get_group_id();
6814
6815
    if (isset($groupId) && $groupId != '') {
6816
        if (!empty($groupIdParam)) {
6817
            return $groupIdParam == $groupId;
6818
        } else {
6819
            return true;
6820
        }
6821
    }
6822
6823
    return false;
6824
}
6825
6826
/**
6827
 * Checks whether a secret key is valid.
6828
 *
6829
 * @param string $original_key_secret - secret key from (webservice) client
6830
 * @param string $security_key        - security key from Chamilo
6831
 *
6832
 * @return bool - true if secret key is valid, false otherwise
6833
 */
6834
function api_is_valid_secret_key($original_key_secret, $security_key)
6835
{
6836
    return $original_key_secret == sha1($security_key);
6837
}
6838
6839
/**
6840
 * Checks whether a user is into course.
6841
 *
6842
 * @param int $course_id - the course id
6843
 * @param int $user_id   - the user id
6844
 *
6845
 * @return bool
6846
 */
6847
function api_is_user_of_course($course_id, $user_id)
6848
{
6849
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6850
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6851
            WHERE
6852
                c_id ="'.intval($course_id).'" AND
6853
                user_id = "'.intval($user_id).'" AND
6854
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6855
    $result = Database::query($sql);
6856
6857
    return Database::num_rows($result) == 1;
6858
}
6859
6860
/**
6861
 * Checks whether the server's operating system is Windows (TM).
6862
 *
6863
 * @return bool - true if the operating system is Windows, false otherwise
6864
 */
6865
function api_is_windows_os()
6866
{
6867
    if (function_exists('php_uname')) {
6868
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6869
        // We expect that this function will always work for Chamilo 1.8.x.
6870
        $os = php_uname();
6871
    }
6872
    // The following methods are not needed, but let them stay, just in case.
6873
    elseif (isset($_ENV['OS'])) {
6874
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6875
        $os = $_ENV['OS'];
6876
    } elseif (defined('PHP_OS')) {
6877
        // PHP_OS means on which OS PHP was compiled, this is why
6878
        // using PHP_OS is the last choice for detection.
6879
        $os = PHP_OS;
6880
    } else {
6881
        return false;
6882
    }
6883
6884
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6885
}
6886
6887
/**
6888
 * This function informs whether the sent request is XMLHttpRequest.
6889
 */
6890
function api_is_xml_http_request()
6891
{
6892
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6893
}
6894
6895
/**
6896
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6897
 *
6898
 * @see http://php.net/manual/en/function.getimagesize.php
6899
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6900
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6901
 *
6902
 * @return int
6903
 */
6904
function api_getimagesize($path)
6905
{
6906
    $image = new Image($path);
6907
6908
    return $image->get_image_size();
6909
}
6910
6911
/**
6912
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6913
 *
6914
 * @author Ivan Tcholakov, MAY-2009.
6915
 *
6916
 * @param int $image         System path or URL of the image
6917
 * @param int $target_width  Targeted width
6918
 * @param int $target_height Targeted height
6919
 *
6920
 * @return array Calculated new width and height
6921
 */
6922
function api_resize_image($image, $target_width, $target_height)
6923
{
6924
    $image_properties = api_getimagesize($image);
6925
6926
    return api_calculate_image_size(
6927
        $image_properties['width'],
6928
        $image_properties['height'],
6929
        $target_width,
6930
        $target_height
6931
    );
6932
}
6933
6934
/**
6935
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6936
 *
6937
 * @author Ivan Tcholakov, MAY-2009.
6938
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6939
 *
6940
 * @param int $image_width   Initial width
6941
 * @param int $image_height  Initial height
6942
 * @param int $target_width  Targeted width
6943
 * @param int $target_height Targeted height
6944
 *
6945
 * @return array Calculated new width and height
6946
 */
6947
function api_calculate_image_size(
6948
    $image_width,
6949
    $image_height,
6950
    $target_width,
6951
    $target_height
6952
) {
6953
    // Only maths is here.
6954
    $result = ['width' => $image_width, 'height' => $image_height];
6955
    if ($image_width <= 0 || $image_height <= 0) {
6956
        return $result;
6957
    }
6958
    $resize_factor_width = $target_width / $image_width;
6959
    $resize_factor_height = $target_height / $image_height;
6960
    $delta_width = $target_width - $image_width * $resize_factor_height;
6961
    $delta_height = $target_height - $image_height * $resize_factor_width;
6962
    if ($delta_width > $delta_height) {
6963
        $result['width'] = ceil($image_width * $resize_factor_height);
6964
        $result['height'] = ceil($image_height * $resize_factor_height);
6965
    } elseif ($delta_width < $delta_height) {
6966
        $result['width'] = ceil($image_width * $resize_factor_width);
6967
        $result['height'] = ceil($image_height * $resize_factor_width);
6968
    } else {
6969
        $result['width'] = ceil($target_width);
6970
        $result['height'] = ceil($target_height);
6971
    }
6972
6973
    return $result;
6974
}
6975
6976
/**
6977
 * Returns a list of Chamilo's tools or
6978
 * checks whether a given identificator is a valid Chamilo's tool.
6979
 *
6980
 * @author Isaac flores paz
6981
 *
6982
 * @param string The tool name to filter
6983
 *
6984
 * @return mixed Filtered string or array
6985
 */
6986
function api_get_tools_lists($my_tool = null)
6987
{
6988
    $tools_list = [
6989
        TOOL_DOCUMENT,
6990
        TOOL_THUMBNAIL,
6991
        TOOL_HOTPOTATOES,
6992
        TOOL_CALENDAR_EVENT,
6993
        TOOL_LINK,
6994
        TOOL_COURSE_DESCRIPTION,
6995
        TOOL_SEARCH,
6996
        TOOL_LEARNPATH,
6997
        TOOL_ANNOUNCEMENT,
6998
        TOOL_FORUM,
6999
        TOOL_THREAD,
7000
        TOOL_POST,
7001
        TOOL_DROPBOX,
7002
        TOOL_QUIZ,
7003
        TOOL_USER,
7004
        TOOL_GROUP,
7005
        TOOL_BLOGS,
7006
        TOOL_CHAT,
7007
        TOOL_STUDENTPUBLICATION,
7008
        TOOL_TRACKING,
7009
        TOOL_HOMEPAGE_LINK,
7010
        TOOL_COURSE_SETTING,
7011
        TOOL_BACKUP,
7012
        TOOL_COPY_COURSE_CONTENT,
7013
        TOOL_RECYCLE_COURSE,
7014
        TOOL_COURSE_HOMEPAGE,
7015
        TOOL_COURSE_RIGHTS_OVERVIEW,
7016
        TOOL_UPLOAD,
7017
        TOOL_COURSE_MAINTENANCE,
7018
        TOOL_SURVEY,
7019
        TOOL_WIKI,
7020
        TOOL_GLOSSARY,
7021
        TOOL_GRADEBOOK,
7022
        TOOL_NOTEBOOK,
7023
        TOOL_ATTENDANCE,
7024
        TOOL_COURSE_PROGRESS,
7025
    ];
7026
    if (empty($my_tool)) {
7027
        return $tools_list;
7028
    }
7029
7030
    return in_array($my_tool, $tools_list) ? $my_tool : '';
7031
}
7032
7033
/**
7034
 * Checks whether we already approved the last version term and condition.
7035
 *
7036
 * @param int user id
7037
 *
7038
 * @return bool true if we pass false otherwise
7039
 */
7040
function api_check_term_condition($userId)
7041
{
7042
    if (api_get_setting('allow_terms_conditions') === 'true') {
7043
        // Check if exists terms and conditions
7044
        if (LegalManager::count() == 0) {
7045
            return true;
7046
        }
7047
7048
        $extraFieldValue = new ExtraFieldValue('user');
7049
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
7050
            $userId,
7051
            'legal_accept'
7052
        );
7053
7054
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
7055
            $result = $data['value'];
7056
            $user_conditions = explode(':', $result);
7057
            $version = $user_conditions[0];
7058
            $langId = $user_conditions[1];
7059
            $realVersion = LegalManager::get_last_version($langId);
7060
7061
            return $version >= $realVersion;
7062
        }
7063
7064
        return false;
7065
    }
7066
7067
    return false;
7068
}
7069
7070
/**
7071
 * Gets all information of a tool into course.
7072
 *
7073
 * @param int The tool id
7074
 *
7075
 * @return array
7076
 */
7077
function api_get_tool_information_by_name($name)
7078
{
7079
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
7080
    $course_id = api_get_course_int_id();
7081
    $sql = "SELECT * FROM $t_tool
7082
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
7083
    $rs = Database::query($sql);
7084
7085
    return Database::fetch_array($rs, 'ASSOC');
7086
}
7087
7088
/**
7089
 * Function used to protect a "global" admin script.
7090
 * The function blocks access when the user has no global platform admin rights.
7091
 * Global admins are the admins that are registered in the main.admin table
7092
 * AND the users who have access to the "principal" portal.
7093
 * That means that there is a record in the main.access_url_rel_user table
7094
 * with his user id and the access_url_id=1.
7095
 *
7096
 * @author Julio Montoya
7097
 *
7098
 * @param int $user_id
7099
 *
7100
 * @return bool
7101
 */
7102
function api_is_global_platform_admin($user_id = null)
7103
{
7104
    $user_id = (int) $user_id;
7105
    if (empty($user_id)) {
7106
        $user_id = api_get_user_id();
7107
    }
7108
    if (api_is_platform_admin_by_id($user_id)) {
7109
        $urlList = api_get_access_url_from_user($user_id);
7110
        // The admin is registered in the first "main" site with access_url_id = 1
7111
        if (in_array(1, $urlList)) {
7112
            return true;
7113
        } else {
7114
            return false;
7115
        }
7116
    }
7117
7118
    return false;
7119
}
7120
7121
/**
7122
 * @param int  $admin_id_to_check
7123
 * @param int  $my_user_id
7124
 * @param bool $allow_session_admin
7125
 *
7126
 * @return bool
7127
 */
7128
function api_global_admin_can_edit_admin(
7129
    $admin_id_to_check,
7130
    $my_user_id = null,
7131
    $allow_session_admin = false
7132
) {
7133
    if (empty($my_user_id)) {
7134
        $my_user_id = api_get_user_id();
7135
    }
7136
7137
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
7138
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
7139
7140
    if ($iam_a_global_admin) {
7141
        // Global admin can edit everything
7142
        return true;
7143
    } else {
7144
        // If i'm a simple admin
7145
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
7146
7147
        if ($allow_session_admin) {
7148
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
7149
        }
7150
7151
        if ($is_platform_admin) {
7152
            if ($user_is_global_admin) {
7153
                return false;
7154
            } else {
7155
                return true;
7156
            }
7157
        } else {
7158
            return false;
7159
        }
7160
    }
7161
}
7162
7163
/**
7164
 * @param int  $admin_id_to_check
7165
 * @param int  $my_user_id
7166
 * @param bool $allow_session_admin
7167
 *
7168
 * @return bool|null
7169
 */
7170
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
7171
{
7172
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
7173
        return true;
7174
    } else {
7175
        api_not_allowed();
7176
    }
7177
}
7178
7179
/**
7180
 * Function used to protect a global admin script.
7181
 * The function blocks access when the user has no global platform admin rights.
7182
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
7183
 *
7184
 * @author Julio Montoya
7185
 */
7186
function api_protect_global_admin_script()
7187
{
7188
    if (!api_is_global_platform_admin()) {
7189
        api_not_allowed();
7190
7191
        return false;
7192
    }
7193
7194
    return true;
7195
}
7196
7197
/**
7198
 * Get active template.
7199
 *
7200
 * @param string    theme type (optional: default)
7201
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
7202
 *
7203
 * @return string actived template path
7204
 */
7205
function api_get_template($path_type = 'rel')
7206
{
7207
    $path_types = ['rel', 'abs'];
7208
    $template_path = '';
7209
    if (in_array($path_type, $path_types)) {
7210
        if ($path_type == 'rel') {
7211
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
7212
        } else {
7213
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
7214
        }
7215
    }
7216
    $actived_theme = 'default';
7217
    if (api_get_setting('active_template')) {
7218
        $actived_theme = api_get_setting('active_template');
7219
    }
7220
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
7221
7222
    return $actived_theme_path;
7223
}
7224
7225
/**
7226
 * Check browser support for specific file types or features
7227
 * This function checks if the user's browser supports a file format or given
7228
 * feature, or returns the current browser and major version when
7229
 * $format=check_browser. Only a limited number of formats and features are
7230
 * checked by this method. Make sure you check its definition first.
7231
 *
7232
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
7233
 *
7234
 * @return bool or return text array if $format=check_browser
7235
 *
7236
 * @author Juan Carlos Raña Trabado
7237
 */
7238
function api_browser_support($format = '')
7239
{
7240
    $browser = new Browser();
7241
    $current_browser = $browser->getBrowser();
7242
    $a_versiontemp = explode('.', $browser->getVersion());
7243
    $current_majorver = $a_versiontemp[0];
7244
7245
    static $result;
7246
7247
    if (isset($result[$format])) {
7248
        return $result[$format];
7249
    }
7250
7251
    // Native svg support
7252
    if ($format == 'svg') {
7253
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7254
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
7255
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
7256
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
7257
            ($current_browser == 'Opera' && $current_majorver >= 9)
7258
        ) {
7259
            $result[$format] = true;
7260
7261
            return true;
7262
        } else {
7263
            $result[$format] = false;
7264
7265
            return false;
7266
        }
7267
    } elseif ($format == 'pdf') {
7268
        // native pdf support
7269
        if (($current_browser == 'Chrome' && $current_majorver >= 6) ||
7270
            ('Firefox' === $current_browser && $current_majorver >= 15)
7271
        ) {
7272
            $result[$format] = true;
7273
7274
            return true;
7275
        } else {
7276
            $result[$format] = false;
7277
7278
            return false;
7279
        }
7280
    } elseif ($format == 'tif' || $format == 'tiff') {
7281
        //native tif support
7282
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7283
            $result[$format] = true;
7284
7285
            return true;
7286
        } else {
7287
            $result[$format] = false;
7288
7289
            return false;
7290
        }
7291
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
7292
        //native ogg, ogv,oga support
7293
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
7294
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
7295
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
7296
            $result[$format] = true;
7297
7298
            return true;
7299
        } else {
7300
            $result[$format] = false;
7301
7302
            return false;
7303
        }
7304
    } elseif ($format == 'mpg' || $format == 'mpeg') {
7305
        //native mpg support
7306
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
7307
            $result[$format] = true;
7308
7309
            return true;
7310
        } else {
7311
            $result[$format] = false;
7312
7313
            return false;
7314
        }
7315
    } elseif ($format == 'mp4') {
7316
        //native mp4 support (TODO: Android, iPhone)
7317
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
7318
            $result[$format] = true;
7319
7320
            return true;
7321
        } else {
7322
            $result[$format] = false;
7323
7324
            return false;
7325
        }
7326
    } elseif ($format == 'mov') {
7327
        //native mov support( TODO:check iPhone)
7328
        if ($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($current_browser == 'Sa...ent_browser == 'iPhone', Probably Intended Meaning: $current_browser == 'Saf...nt_browser == 'iPhone')
Loading history...
7329
            $result[$format] = true;
7330
7331
            return true;
7332
        } else {
7333
            $result[$format] = false;
7334
7335
            return false;
7336
        }
7337
    } elseif ($format == 'avi') {
7338
        //native avi support
7339
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7340
            $result[$format] = true;
7341
7342
            return true;
7343
        } else {
7344
            $result[$format] = false;
7345
7346
            return false;
7347
        }
7348
    } elseif ($format == 'wmv') {
7349
        //native wmv support
7350
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7351
            $result[$format] = true;
7352
7353
            return true;
7354
        } else {
7355
            $result[$format] = false;
7356
7357
            return false;
7358
        }
7359
    } elseif ($format == 'webm') {
7360
        //native webm support (TODO:check IE9, Chrome9, Android)
7361
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7362
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7363
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7364
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
7365
            $current_browser == 'Android'
7366
        ) {
7367
            $result[$format] = true;
7368
7369
            return true;
7370
        } else {
7371
            $result[$format] = false;
7372
7373
            return false;
7374
        }
7375
    } elseif ($format == 'wav') {
7376
        //native wav support (only some codecs !)
7377
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7378
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
7379
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7380
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7381
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
7382
            $current_browser == 'Android' ||
7383
            $current_browser == 'iPhone'
7384
        ) {
7385
            $result[$format] = true;
7386
7387
            return true;
7388
        } else {
7389
            $result[$format] = false;
7390
7391
            return false;
7392
        }
7393
    } elseif ($format == 'mid' || $format == 'kar') {
7394
        //native midi support (TODO:check Android)
7395
        if ($current_browser == 'Opera' && $current_majorver >= 9 || $current_browser == 'Android') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($current_browser == 'Op...nt_browser == 'Android', Probably Intended Meaning: $current_browser == 'Ope...t_browser == 'Android')
Loading history...
7396
            $result[$format] = true;
7397
7398
            return true;
7399
        } else {
7400
            $result[$format] = false;
7401
7402
            return false;
7403
        }
7404
    } elseif ($format == 'wma') {
7405
        //native wma support
7406
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7407
            $result[$format] = true;
7408
7409
            return true;
7410
        } else {
7411
            $result[$format] = false;
7412
7413
            return false;
7414
        }
7415
    } elseif ($format == 'au') {
7416
        //native au support
7417
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7418
            $result[$format] = true;
7419
7420
            return true;
7421
        } else {
7422
            $result[$format] = false;
7423
7424
            return false;
7425
        }
7426
    } elseif ($format == 'mp3') {
7427
        //native mp3 support (TODO:check Android, iPhone)
7428
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
7429
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
7430
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7431
            $current_browser == 'Android' ||
7432
            $current_browser == 'iPhone' ||
7433
            $current_browser == 'Firefox'
7434
        ) {
7435
            $result[$format] = true;
7436
7437
            return true;
7438
        } else {
7439
            $result[$format] = false;
7440
7441
            return false;
7442
        }
7443
    } elseif ($format == 'autocapitalize') {
7444
        // Help avoiding showing the autocapitalize option if the browser doesn't
7445
        // support it: this attribute is against the HTML5 standard
7446
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
7447
            return true;
7448
        } else {
7449
            return false;
7450
        }
7451
    } elseif ($format == "check_browser") {
7452
        $array_check_browser = [$current_browser, $current_majorver];
7453
7454
        return $array_check_browser;
7455
    } else {
7456
        $result[$format] = false;
7457
7458
        return false;
7459
    }
7460
}
7461
7462
/**
7463
 * This function checks if exist path and file browscap.ini
7464
 * In order for this to work, your browscap configuration setting in php.ini
7465
 * must point to the correct location of the browscap.ini file on your system
7466
 * http://php.net/manual/en/function.get-browser.php.
7467
 *
7468
 * @return bool
7469
 *
7470
 * @author Juan Carlos Raña Trabado
7471
 */
7472
function api_check_browscap()
7473
{
7474
    $setting = ini_get('browscap');
7475
    if ($setting) {
7476
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7477
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7478
            return true;
7479
        }
7480
    }
7481
7482
    return false;
7483
}
7484
7485
/**
7486
 * Returns the <script> HTML tag.
7487
 */
7488
function api_get_js($file)
7489
{
7490
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7491
}
7492
7493
/**
7494
 * Returns the <script> HTML tag.
7495
 *
7496
 * @return string
7497
 */
7498
function api_get_asset($file)
7499
{
7500
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
7501
}
7502
7503
/**
7504
 * Returns the <script> HTML tag.
7505
 *
7506
 * @param string $file
7507
 * @param string $media
7508
 *
7509
 * @return string
7510
 */
7511
function api_get_css_asset($file, $media = 'screen')
7512
{
7513
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7514
}
7515
7516
/**
7517
 * Returns the <link> HTML tag.
7518
 *
7519
 * @param string $file
7520
 * @param string $media
7521
 */
7522
function api_get_css($file, $media = 'screen')
7523
{
7524
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7525
}
7526
7527
/**
7528
 * Returns the js header to include the jquery library.
7529
 */
7530
function api_get_jquery_js()
7531
{
7532
    return api_get_asset('jquery/dist/jquery.min.js');
7533
}
7534
7535
/**
7536
 * Returns the jquery path.
7537
 *
7538
 * @return string
7539
 */
7540
function api_get_jquery_web_path()
7541
{
7542
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
7543
}
7544
7545
/**
7546
 * @return string
7547
 */
7548
function api_get_jquery_ui_js_web_path()
7549
{
7550
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7551
}
7552
7553
/**
7554
 * @return string
7555
 */
7556
function api_get_jquery_ui_css_web_path()
7557
{
7558
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7559
}
7560
7561
/**
7562
 * Returns the jquery-ui library js headers.
7563
 *
7564
 * @param   bool    add the jqgrid library
7565
 *
7566
 * @return string html tags
7567
 */
7568
function api_get_jquery_ui_js($include_jqgrid = false)
7569
{
7570
    $libraries = [];
7571
    if ($include_jqgrid) {
7572
        $libraries[] = 'jqgrid';
7573
    }
7574
7575
    return api_get_jquery_libraries_js($libraries);
7576
}
7577
7578
function api_get_jqgrid_js()
7579
{
7580
    return api_get_jquery_libraries_js(['jqgrid']);
7581
}
7582
7583
/**
7584
 * Returns the jquery library js and css headers.
7585
 *
7586
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
7587
 * @param   bool    add the jquery library
7588
 *
7589
 * @return string html tags
7590
 */
7591
function api_get_jquery_libraries_js($libraries)
7592
{
7593
    $js = '';
7594
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
7595
7596
    //jqgrid js and css
7597
    if (in_array('jqgrid', $libraries)) {
7598
        $languaje = 'en';
7599
        $platform_isocode = strtolower(api_get_language_isocode());
7600
7601
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7602
        $jqgrid_langs = [
7603
            'bg', 'bg1251', 'cat', 'cn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fr', 'gl', 'he', 'hu', 'is', 'it', 'ja', 'nl', 'no', 'pl', 'pt-br', 'pt', 'ro', 'ru', 'sk', 'sr', 'sv', 'tr', 'ua',
7604
        ];
7605
7606
        if (in_array($platform_isocode, $jqgrid_langs)) {
7607
            $languaje = $platform_isocode;
7608
        }
7609
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
7610
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
7611
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
7612
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
7613
    }
7614
7615
    //Document multiple upload funcionality
7616
    if (in_array('jquery-upload', $libraries)) {
7617
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7618
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7619
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7620
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7621
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7622
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7623
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7624
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7625
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7626
7627
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7628
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7629
    }
7630
7631
    // jquery datepicker
7632
    if (in_array('datepicker', $libraries)) {
7633
        $languaje = 'en-GB';
7634
        $platform_isocode = strtolower(api_get_language_isocode());
7635
7636
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7637
        $datapicker_langs = [
7638
            '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',
7639
        ];
7640
        if (in_array($platform_isocode, $datapicker_langs)) {
7641
            $languaje = $platform_isocode;
7642
        }
7643
7644
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7645
        $script = '<script>
7646
        $(function(){
7647
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7648
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7649
        });
7650
        </script>
7651
        ';
7652
        $js .= $script;
7653
    }
7654
7655
    return $js;
7656
}
7657
7658
/**
7659
 * Returns the URL to the course or session, removing the complexity of the URL
7660
 * building piece by piece.
7661
 *
7662
 * This function relies on api_get_course_info()
7663
 *
7664
 * @param string $courseCode The course code - optional (takes it from context if not given)
7665
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7666
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7667
 *
7668
 * @return string The URL to a course, a session, or empty string if nothing works e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
7669
 *
7670
 * @author  Julio Montoya <[email protected]>
7671
 */
7672
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7673
{
7674
    $courseDirectory = '';
7675
    $url = '';
7676
    // If courseCode not set, get context or []
7677
    if (empty($courseCode)) {
7678
        $courseInfo = api_get_course_info();
7679
    } else {
7680
        $courseInfo = api_get_course_info($courseCode);
7681
    }
7682
7683
    // If course defined, get directory, otherwise keep empty string
7684
    if (!empty($courseInfo['directory'])) {
7685
        $courseDirectory = $courseInfo['directory'];
7686
    }
7687
7688
    // If sessionId not set, get context or 0
7689
    if (empty($sessionId)) {
7690
        $sessionId = api_get_session_id();
7691
    }
7692
7693
    // If groupId not set, get context or 0
7694
    if (empty($groupId)) {
7695
        $groupId = api_get_group_id();
7696
    }
7697
7698
    // Build the URL
7699
    if (!empty($courseDirectory)) {
7700
        // directory not empty, so we do have a course
7701
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7702
    } elseif (!empty($sessionId) && api_get_configuration_value('remove_session_url') !== true) {
7703
        // if the course was unset and the session was set, send directly to the session
7704
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7705
    }
7706
    // if not valid combination was found, return an empty string
7707
    return $url;
7708
}
7709
7710
/**
7711
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7712
 *
7713
 * @return bool true if multi site is enabled
7714
 */
7715
function api_get_multiple_access_url()
7716
{
7717
    global $_configuration;
7718
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7719
        return true;
7720
    }
7721
7722
    return false;
7723
}
7724
7725
/**
7726
 * Just a synonym for api_get_multiple_access_url().
7727
 *
7728
 * @return bool
7729
 */
7730
function api_is_multiple_url_enabled()
7731
{
7732
    return api_get_multiple_access_url();
7733
}
7734
7735
/**
7736
 * Returns a md5 unique id.
7737
 *
7738
 * @todo add more parameters
7739
 */
7740
function api_get_unique_id()
7741
{
7742
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7743
7744
    return $id;
7745
}
7746
7747
/**
7748
 * Get home path.
7749
 *
7750
 * @return string
7751
 */
7752
function api_get_home_path()
7753
{
7754
    // FIX : Start the routing determination from central path definition
7755
    $home = api_get_path(SYS_HOME_PATH);
7756
    if (api_get_multiple_access_url()) {
7757
        $access_url_id = api_get_current_access_url_id();
7758
        $url_info = api_get_access_url($access_url_id);
7759
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
7760
        $clean_url = api_replace_dangerous_char($url);
7761
        $clean_url = str_replace('/', '-', $clean_url);
7762
        $clean_url .= '/';
7763
        if ($clean_url != 'localhost/') {
7764
            // means that the multiple URL was not well configured we don't rename the $home variable
7765
            return "{$home}{$clean_url}";
7766
        }
7767
    }
7768
7769
    return $home;
7770
}
7771
7772
/**
7773
 * @param int Course id
7774
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7775
 * @param int the item id (tool id, exercise id, lp id)
7776
 *
7777
 * @return bool
7778
 */
7779
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7780
{
7781
    if (api_is_platform_admin()) {
7782
        return false;
7783
    }
7784
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
7785
        if (empty($course_code)) {
7786
            $course_code = api_get_course_id();
7787
        }
7788
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7789
        $item_id = intval($item_id);
7790
        $link_type = intval($link_type);
7791
        $course_code = Database::escape_string($course_code);
7792
        $sql = "SELECT locked FROM $table
7793
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7794
        $result = Database::query($sql);
7795
        if (Database::num_rows($result)) {
7796
            return true;
7797
        }
7798
    }
7799
7800
    return false;
7801
}
7802
7803
/**
7804
 * Blocks a page if the item was added in a gradebook.
7805
 *
7806
 * @param int       exercise id, work id, thread id,
7807
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7808
 * see gradebook/lib/be/linkfactory
7809
 * @param string    course code
7810
 *
7811
 * @return false|null
7812
 */
7813
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7814
{
7815
    if (api_is_platform_admin()) {
7816
        return false;
7817
    }
7818
7819
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7820
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
7821
        api_not_allowed(true, $message);
7822
    }
7823
}
7824
7825
/**
7826
 * Checks the PHP version installed is enough to run Chamilo.
7827
 *
7828
 * @param string Include path (used to load the error page)
7829
 */
7830
function api_check_php_version($my_inc_path = null)
7831
{
7832
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
7833
        $global_error_code = 1;
7834
        // Incorrect PHP version
7835
        $global_page = $my_inc_path.'global_error_message.inc.php';
7836
        if (file_exists($global_page)) {
7837
            require $global_page;
7838
        }
7839
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
7840
    }
7841
}
7842
7843
/**
7844
 * Checks whether the Archive directory is present and writeable. If not,
7845
 * prints a warning message.
7846
 */
7847
function api_check_archive_dir()
7848
{
7849
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7850
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
7851
        api_not_allowed(true, $message);
7852
    }
7853
}
7854
7855
/**
7856
 * Returns an array of global configuration settings which should be ignored
7857
 * when printing the configuration settings screens.
7858
 *
7859
 * @return array Array of strings, each identifying one of the excluded settings
7860
 */
7861
function api_get_locked_settings()
7862
{
7863
    return [
7864
        'server_type',
7865
        'permanently_remove_deleted_files',
7866
        'account_valid_duration',
7867
        'service_ppt2lp',
7868
        'wcag_anysurfer_public_pages',
7869
        'upload_extensions_list_type',
7870
        'upload_extensions_blacklist',
7871
        'upload_extensions_whitelist',
7872
        'upload_extensions_skip',
7873
        'upload_extensions_replace_by',
7874
        'hide_dltt_markup',
7875
        'split_users_upload_directory',
7876
        'permissions_for_new_directories',
7877
        'permissions_for_new_files',
7878
        'platform_charset',
7879
        'ldap_description',
7880
        'cas_activate',
7881
        'cas_server',
7882
        'cas_server_uri',
7883
        'cas_port',
7884
        'cas_protocol',
7885
        'cas_add_user_activate',
7886
        'update_user_info_cas_with_ldap',
7887
        'languagePriority1',
7888
        'languagePriority2',
7889
        'languagePriority3',
7890
        'languagePriority4',
7891
        'login_is_email',
7892
        'chamilo_database_version',
7893
    ];
7894
}
7895
7896
/**
7897
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7898
 * false if he isn't. If the user ID is given and is an integer, then the same
7899
 * ID is simply returned.
7900
 *
7901
 * @param  int User ID
7902
 *
7903
 * @return bool Integer User ID is logged in, or false otherwise
7904
 */
7905
function api_user_is_login($user_id = null)
7906
{
7907
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
7908
7909
    return $user_id && !api_is_anonymous();
7910
}
7911
7912
/**
7913
 * Guess the real ip for register in the database, even in reverse proxy cases.
7914
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7915
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7916
 * Note: the result of this function is not SQL-safe. Please escape it before
7917
 * inserting in a database.
7918
 *
7919
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7920
 *
7921
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7922
 *
7923
 * @version CEV CHANGE 24APR2012
7924
 */
7925
function api_get_real_ip()
7926
{
7927
    $ip = trim($_SERVER['REMOTE_ADDR']);
7928
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7929
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7930
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7931
        } else {
7932
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7933
        }
7934
        $ip = trim($ip1);
7935
    }
7936
7937
    return $ip;
7938
}
7939
7940
/**
7941
 * Checks whether an IP is included inside an IP range.
7942
 *
7943
 * @param string IP address
7944
 * @param string IP range
7945
 * @param string $ip
7946
 *
7947
 * @return bool True if IP is in the range, false otherwise
7948
 *
7949
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7950
 * @author Yannick Warnier for improvements and managment of multiple ranges
7951
 *
7952
 * @todo check for IPv6 support
7953
 */
7954
function api_check_ip_in_range($ip, $range)
7955
{
7956
    if (empty($ip) or empty($range)) {
7957
        return false;
7958
    }
7959
    $ip_ip = ip2long($ip);
7960
    // divide range param into array of elements
7961
    if (strpos($range, ',') !== false) {
7962
        $ranges = explode(',', $range);
7963
    } else {
7964
        $ranges = [$range];
7965
    }
7966
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7967
        $range = trim($range);
7968
        if (empty($range)) {
7969
            continue;
7970
        }
7971
        if (strpos($range, '/') === false) {
7972
            if (strcmp($ip, $range) === 0) {
7973
                return true; // there is a direct IP match, return OK
7974
            }
7975
            continue; //otherwise, get to the next range
7976
        }
7977
        // the range contains a "/", so analyse completely
7978
        list($net, $mask) = explode("/", $range);
7979
7980
        $ip_net = ip2long($net);
7981
        // mask binary magic
7982
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7983
7984
        $ip_ip_net = $ip_ip & $ip_mask;
7985
        if ($ip_ip_net == $ip_net) {
7986
            return true;
7987
        }
7988
    }
7989
7990
    return false;
7991
}
7992
7993
function api_check_user_access_to_legal($courseInfo)
7994
{
7995
    if (empty($courseInfo)) {
7996
        return false;
7997
    }
7998
7999
    $visibility = (int) $courseInfo['visibility'];
8000
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
8001
8002
    return
8003
        in_array($visibility, $visibilityList) ||
8004
        api_is_drh() ||
8005
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
8006
}
8007
8008
/**
8009
 * Checks if the global chat is enabled or not.
8010
 *
8011
 * @return bool
8012
 */
8013
function api_is_global_chat_enabled()
8014
{
8015
    return
8016
        !api_is_anonymous() &&
8017
        api_get_setting('allow_global_chat') === 'true' &&
8018
        api_get_setting('allow_social_tool') === 'true';
8019
}
8020
8021
/**
8022
 * @todo Fix tool_visible_by_default_at_creation labels
8023
 *
8024
 * @param int   $item_id
8025
 * @param int   $tool_id
8026
 * @param int   $group_id   id
8027
 * @param array $courseInfo
8028
 * @param int   $sessionId
8029
 * @param int   $userId
8030
 */
8031
function api_set_default_visibility(
8032
    $item_id,
8033
    $tool_id,
8034
    $group_id = 0,
8035
    $courseInfo = [],
8036
    $sessionId = 0,
8037
    $userId = 0
8038
) {
8039
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
8040
    $courseId = $courseInfo['real_id'];
8041
    $courseCode = $courseInfo['code'];
8042
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
8043
    $userId = empty($userId) ? api_get_user_id() : $userId;
8044
8045
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
8046
    if (is_null($group_id)) {
8047
        $group_id = 0;
8048
    } else {
8049
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
8050
    }
8051
8052
    $groupInfo = [];
8053
    if (!empty($group_id)) {
8054
        $groupInfo = GroupManager::get_group_properties($group_id);
8055
    }
8056
    $original_tool_id = $tool_id;
8057
8058
    switch ($tool_id) {
8059
        case TOOL_LINK:
8060
        case TOOL_LINK_CATEGORY:
8061
            $tool_id = 'links';
8062
            break;
8063
        case TOOL_DOCUMENT:
8064
            $tool_id = 'documents';
8065
            break;
8066
        case TOOL_LEARNPATH:
8067
            $tool_id = 'learning';
8068
            break;
8069
        case TOOL_ANNOUNCEMENT:
8070
            $tool_id = 'announcements';
8071
            break;
8072
        case TOOL_FORUM:
8073
        case TOOL_FORUM_CATEGORY:
8074
        case TOOL_FORUM_THREAD:
8075
            $tool_id = 'forums';
8076
            break;
8077
        case TOOL_QUIZ:
8078
            $tool_id = 'quiz';
8079
            break;
8080
    }
8081
    $setting = api_get_setting('tool_visible_by_default_at_creation');
8082
8083
    if (isset($setting[$tool_id])) {
8084
        $visibility = 'invisible';
8085
        if ($setting[$tool_id] == 'true') {
8086
            $visibility = 'visible';
8087
        }
8088
8089
        // Read the portal and course default visibility
8090
        if ($tool_id === 'documents') {
8091
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
8092
        }
8093
8094
        api_item_property_update(
8095
            $courseInfo,
8096
            $original_tool_id,
8097
            $item_id,
8098
            $visibility,
8099
            $userId,
8100
            $groupInfo,
8101
            null,
8102
            null,
8103
            null,
8104
            $sessionId
8105
        );
8106
8107
        // Fixes default visibility for tests
8108
        switch ($original_tool_id) {
8109
            case TOOL_QUIZ:
8110
                if (empty($sessionId)) {
8111
                    $objExerciseTmp = new Exercise($courseId);
8112
                    $objExerciseTmp->read($item_id);
8113
                    if ($visibility == 'visible') {
8114
                        $objExerciseTmp->enable();
8115
                        $objExerciseTmp->save();
8116
                    } else {
8117
                        $objExerciseTmp->disable();
8118
                        $objExerciseTmp->save();
8119
                    }
8120
                }
8121
                break;
8122
        }
8123
    }
8124
}
8125
8126
/**
8127
 * @return string
8128
 */
8129
function api_get_security_key()
8130
{
8131
    return api_get_configuration_value('security_key');
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_configura...n_value('security_key') also could return the type boolean which is incompatible with the documented return type string.
Loading history...
8132
}
8133
8134
/**
8135
 * @param int $user_id
8136
 * @param int $courseId
8137
 * @param int $session_id
8138
 *
8139
 * @return array
8140
 */
8141
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
8142
{
8143
    $user_roles = [];
8144
    $courseInfo = api_get_course_info_by_id($courseId);
8145
    $course_code = $courseInfo['code'];
8146
8147
    $url_id = api_get_current_access_url_id();
8148
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
8149
        $user_roles[] = PLATFORM_ADMIN;
8150
    }
8151
8152
    /*if (api_is_drh()) {
8153
        $user_roles[] = DRH;
8154
    }*/
8155
8156
    if (!empty($session_id)) {
8157
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
8158
            $user_roles[] = SESSION_GENERAL_COACH;
8159
        }
8160
    }
8161
8162
    if (!empty($course_code)) {
8163
        if (empty($session_id)) {
8164
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
8165
                $user_roles[] = COURSEMANAGER;
8166
            }
8167
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
8168
                $user_roles[] = COURSE_TUTOR;
8169
            }
8170
8171
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
8172
                $user_roles[] = COURSE_STUDENT;
8173
            }
8174
        } else {
8175
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
8176
                $user_id,
8177
                $courseId,
8178
                $session_id
8179
            );
8180
8181
            if (!empty($user_status_in_session)) {
8182
                if ($user_status_in_session == 0) {
8183
                    $user_roles[] = SESSION_STUDENT;
8184
                }
8185
                if ($user_status_in_session == 2) {
8186
                    $user_roles[] = SESSION_COURSE_COACH;
8187
                }
8188
            }
8189
8190
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
8191
               $user_roles[] = SESSION_COURSE_COACH;
8192
            }*/
8193
        }
8194
    }
8195
8196
    return $user_roles;
8197
}
8198
8199
/**
8200
 * @param int $courseId
8201
 * @param int $session_id
8202
 *
8203
 * @return bool
8204
 */
8205
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
8206
{
8207
    if (api_is_platform_admin()) {
8208
        return true;
8209
    }
8210
8211
    $user_id = api_get_user_id();
8212
8213
    if (empty($courseId)) {
8214
        $courseId = api_get_course_int_id();
8215
    }
8216
8217
    if (empty($session_id)) {
8218
        $session_id = api_get_session_id();
8219
    }
8220
8221
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
8222
8223
    if (in_array(SESSION_COURSE_COACH, $roles)) {
8224
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
8225
        return true;
8226
    } else {
8227
        if (in_array(COURSEMANAGER, $roles)) {
8228
            return true;
8229
        }
8230
8231
        return false;
8232
    }
8233
}
8234
8235
/**
8236
 * @param string $file
8237
 *
8238
 * @return string
8239
 */
8240
function api_get_js_simple($file)
8241
{
8242
    return '<script src="'.$file.'"></script>'."\n";
8243
}
8244
8245
function api_set_settings_and_plugins()
8246
{
8247
    global $_configuration;
8248
    $_setting = [];
8249
    $_plugins = [];
8250
8251
    // access_url == 1 is the default chamilo location
8252
    $settings_by_access_list = [];
8253
    $access_url_id = api_get_current_access_url_id();
8254
    if ($access_url_id != 1) {
8255
        $url_info = api_get_access_url($_configuration['access_url']);
8256
        if ($url_info['active'] == 1) {
8257
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
8258
            foreach ($settings_by_access as &$row) {
8259
                if (empty($row['variable'])) {
8260
                    $row['variable'] = 0;
8261
                }
8262
                if (empty($row['subkey'])) {
8263
                    $row['subkey'] = 0;
8264
                }
8265
                if (empty($row['category'])) {
8266
                    $row['category'] = 0;
8267
                }
8268
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
8269
            }
8270
        }
8271
    }
8272
8273
    $result = api_get_settings(null, 'list', 1);
8274
8275
    foreach ($result as &$row) {
8276
        if ($access_url_id != 1) {
8277
            if ($url_info['active'] == 1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $url_info does not seem to be defined for all execution paths leading up to this point.
Loading history...
8278
                $var = empty($row['variable']) ? 0 : $row['variable'];
8279
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
8280
                $category = empty($row['category']) ? 0 : $row['category'];
8281
            }
8282
8283
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
8284
                if (isset($settings_by_access_list[$var]) &&
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $var does not seem to be defined for all execution paths leading up to this point.
Loading history...
8285
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $subkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
8286
                    if ($row['subkey'] == null) {
8287
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8288
                    } else {
8289
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8290
                    }
8291
                } else {
8292
                    if ($row['subkey'] == null) {
8293
                        $_setting[$row['variable']] = $row['selected_value'];
8294
                    } else {
8295
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8296
                    }
8297
                }
8298
            } else {
8299
                if ($row['subkey'] == null) {
8300
                    $_setting[$row['variable']] = $row['selected_value'];
8301
                } else {
8302
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8303
                }
8304
            }
8305
        } else {
8306
            if ($row['subkey'] == null) {
8307
                $_setting[$row['variable']] = $row['selected_value'];
8308
            } else {
8309
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8310
            }
8311
        }
8312
    }
8313
8314
    $result = api_get_settings('Plugins', 'list', $access_url_id);
8315
    $_plugins = [];
8316
    foreach ($result as &$row) {
8317
        $key = &$row['variable'];
8318
        if (is_string($_setting[$key])) {
8319
            $_setting[$key] = [];
8320
        }
8321
        $_setting[$key][] = $row['selected_value'];
8322
        $_plugins[$key][] = $row['selected_value'];
8323
    }
8324
8325
    $_SESSION['_setting'] = $_setting;
8326
    $_SESSION['_plugins'] = $_plugins;
8327
}
8328
8329
/**
8330
 * Modify default memory_limit and max_execution_time limits
8331
 * Needed when processing long tasks.
8332
 */
8333
function api_set_more_memory_and_time_limits()
8334
{
8335
    if (function_exists('ini_set')) {
8336
        api_set_memory_limit('2048M');
8337
        ini_set('max_execution_time', 3600);
8338
    }
8339
}
8340
8341
/**
8342
 * Tries to set memory limit, if authorized and new limit is higher than current.
8343
 *
8344
 * @param string $mem New memory limit
8345
 *
8346
 * @return bool True on success, false on failure or current is higher than suggested
8347
 * @assert (null) === false
8348
 * @assert (-1) === false
8349
 * @assert (0) === true
8350
 * @assert ('1G') === true
8351
 */
8352
function api_set_memory_limit($mem)
8353
{
8354
    //if ini_set() not available, this function is useless
8355
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
8356
        return false;
8357
    }
8358
8359
    $memory_limit = ini_get('memory_limit');
8360
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8361
        ini_set('memory_limit', $mem);
8362
8363
        return true;
8364
    }
8365
8366
    return false;
8367
}
8368
8369
/**
8370
 * Gets memory limit in bytes.
8371
 *
8372
 * @param string The memory size (128M, 1G, 1000K, etc)
8373
 *
8374
 * @return int
8375
 * @assert (null) === false
8376
 * @assert ('1t')  === 1099511627776
8377
 * @assert ('1g')  === 1073741824
8378
 * @assert ('1m')  === 1048576
8379
 * @assert ('100k') === 102400
8380
 */
8381
function api_get_bytes_memory_limit($mem)
8382
{
8383
    $size = strtolower(substr($mem, -1));
8384
8385
    switch ($size) {
8386
        case 't':
8387
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8388
            break;
8389
        case 'g':
8390
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8391
            break;
8392
        case 'm':
8393
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8394
            break;
8395
        case 'k':
8396
            $mem = intval(substr($mem, 0, -1)) * 1024;
8397
            break;
8398
        default:
8399
            // we assume it's integer only
8400
            $mem = intval($mem);
8401
            break;
8402
    }
8403
8404
    return $mem;
8405
}
8406
8407
/**
8408
 * Finds all the information about a user from username instead of user id.
8409
 *
8410
 * @param string $officialCode
8411
 *
8412
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8413
 *
8414
 * @author Yannick Warnier <[email protected]>
8415
 */
8416
function api_get_user_info_from_official_code($officialCode)
8417
{
8418
    if (empty($officialCode)) {
8419
        return false;
8420
    }
8421
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8422
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8423
    $result = Database::query($sql);
8424
    if (Database::num_rows($result) > 0) {
8425
        $result_array = Database::fetch_array($result);
8426
8427
        return _api_format_user($result_array);
8428
    }
8429
8430
    return false;
8431
}
8432
8433
/**
8434
 * @param string $usernameInputId
8435
 * @param string $passwordInputId
8436
 *
8437
 * @return string|null
8438
 */
8439
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8440
{
8441
    $checkPass = api_get_setting('allow_strength_pass_checker');
8442
    $useStrengthPassChecker = $checkPass === 'true';
8443
8444
    if ($useStrengthPassChecker === false) {
8445
        return null;
8446
    }
8447
8448
    $translations = [
8449
        'wordLength' => get_lang('PasswordIsTooShort'),
8450
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
8451
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
8452
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
8453
        'wordRepetitions' => get_lang('TooManyRepetitions'),
8454
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
8455
        'errorList' => get_lang('ErrorsFound'),
8456
        'veryWeak' => get_lang('PasswordVeryWeak'),
8457
        'weak' => get_lang('PasswordWeak'),
8458
        'normal' => get_lang('PasswordNormal'),
8459
        'medium' => get_lang('PasswordMedium'),
8460
        'strong' => get_lang('PasswordStrong'),
8461
        'veryStrong' => get_lang('PasswordVeryStrong'),
8462
    ];
8463
8464
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
8465
    $js .= "<script>
8466
    var errorMessages = {
8467
        password_to_short : \"".get_lang('PasswordIsTooShort')."\",
8468
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
8469
    };
8470
8471
    $(function() {
8472
        var lang = ".json_encode($translations).";
8473
        var options = {
8474
            onLoad : function () {
8475
                //$('#messages').text('Start typing password');
8476
            },
8477
            onKeyUp: function (evt) {
8478
                $(evt.target).pwstrength('outputErrorList');
8479
            },
8480
            errorMessages : errorMessages,
8481
            viewports: {
8482
                progress: '#password_progress',
8483
                verdict: '#password-verdict',
8484
                errors: '#password-errors'
8485
            },
8486
            usernameField: '$usernameInputId'
8487
        };
8488
        options.i18n = {
8489
            t: function (key) {
8490
                var result = lang[key];
8491
                return result === key ? '' : result; // This assumes you return the
8492
            }
8493
        };
8494
        $('".$passwordInputId."').pwstrength(options);
8495
    });
8496
    </script>";
8497
8498
    return $js;
8499
}
8500
8501
/**
8502
 * create an user extra field called 'captcha_blocked_until_date'.
8503
 *
8504
 * @param string $username
8505
 *
8506
 * @return bool
8507
 */
8508
function api_block_account_captcha($username)
8509
{
8510
    $userInfo = api_get_user_info_from_username($username);
8511
    if (empty($userInfo)) {
8512
        return false;
8513
    }
8514
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8515
    $time = time() + $minutesToBlock * 60;
8516
    UserManager::update_extra_field_value(
8517
        $userInfo['user_id'],
8518
        'captcha_blocked_until_date',
8519
        api_get_utc_datetime($time)
8520
    );
8521
8522
    return true;
8523
}
8524
8525
/**
8526
 * @param string $username
8527
 *
8528
 * @return bool
8529
 */
8530
function api_clean_account_captcha($username)
8531
{
8532
    $userInfo = api_get_user_info_from_username($username);
8533
    if (empty($userInfo)) {
8534
        return false;
8535
    }
8536
    Session::erase('loginFailedCount');
8537
    UserManager::update_extra_field_value(
8538
        $userInfo['user_id'],
8539
        'captcha_blocked_until_date',
8540
        null
8541
    );
8542
8543
    return true;
8544
}
8545
8546
/**
8547
 * @param string $username
8548
 *
8549
 * @return bool
8550
 */
8551
function api_get_user_blocked_by_captcha($username)
8552
{
8553
    $userInfo = api_get_user_info_from_username($username);
8554
    if (empty($userInfo)) {
8555
        return false;
8556
    }
8557
    $data = UserManager::get_extra_user_data_by_field(
8558
        $userInfo['user_id'],
8559
        'captcha_blocked_until_date'
8560
    );
8561
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8562
        return $data['captcha_blocked_until_date'];
8563
    }
8564
8565
    return false;
8566
}
8567
8568
/**
8569
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8570
 * Postfix the text with "..." if it has been truncated.
8571
 *
8572
 * @param string $text
8573
 * @param int    $number
8574
 *
8575
 * @return string
8576
 *
8577
 * @author hubert borderiou
8578
 */
8579
function api_get_short_text_from_html($text, $number)
8580
{
8581
    // Delete script and style tags
8582
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8583
    $text = api_html_entity_decode($text);
8584
    $out_res = api_remove_tags_with_space($text, false);
8585
    $postfix = "...";
8586
    if (strlen($out_res) > $number) {
8587
        $out_res = substr($out_res, 0, $number).$postfix;
8588
    }
8589
8590
    return $out_res;
8591
}
8592
8593
/**
8594
 * Replace tags with a space in a text.
8595
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8596
 *
8597
 * @return string
8598
 *
8599
 * @author hubert borderiou
8600
 */
8601
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8602
{
8603
    $out_res = $in_html;
8604
    if ($in_double_quote_replace) {
8605
        $out_res = str_replace('"', "''", $out_res);
8606
    }
8607
    // avoid text stuck together when tags are removed, adding a space after >
8608
    $out_res = str_replace(">", "> ", $out_res);
8609
    $out_res = strip_tags($out_res);
8610
8611
    return $out_res;
8612
}
8613
8614
/**
8615
 * If true, the drh can access all content (courses, users) inside a session.
8616
 *
8617
 * @return bool
8618
 */
8619
function api_drh_can_access_all_session_content()
8620
{
8621
    return api_get_setting('drh_can_access_all_session_content') === 'true';
8622
}
8623
8624
/**
8625
 * @param string $tool
8626
 * @param string $setting
8627
 * @param int    $defaultValue
8628
 *
8629
 * @return string
8630
 */
8631
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8632
{
8633
    global $_configuration;
8634
    if (isset($_configuration[$tool]) &&
8635
        isset($_configuration[$tool]['default_settings']) &&
8636
        isset($_configuration[$tool]['default_settings'][$setting])
8637
    ) {
8638
        return $_configuration[$tool]['default_settings'][$setting];
8639
    }
8640
8641
    return $defaultValue;
8642
}
8643
8644
/**
8645
 * Checks if user can login as another user.
8646
 *
8647
 * @param int $loginAsUserId the user id to log in
8648
 * @param int $userId        my user id
8649
 *
8650
 * @return bool
8651
 */
8652
function api_can_login_as($loginAsUserId, $userId = null)
8653
{
8654
    if (empty($userId)) {
8655
        $userId = api_get_user_id();
8656
    }
8657
    if ($loginAsUserId == $userId) {
8658
        return false;
8659
    }
8660
8661
    if (empty($loginAsUserId)) {
8662
        return false;
8663
    }
8664
8665
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8666
        return false;
8667
    }
8668
8669
    // Check if the user to login is an admin
8670
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8671
        // Only super admins can login to admin accounts
8672
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8673
            return false;
8674
        }
8675
    }
8676
8677
    $userInfo = api_get_user_info($loginAsUserId);
8678
    $isDrh = function () use ($loginAsUserId) {
8679
        if (api_is_drh()) {
8680
            if (api_drh_can_access_all_session_content()) {
8681
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8682
                    'drh_all',
8683
                    api_get_user_id()
8684
                );
8685
                $userList = [];
8686
                if (is_array($users)) {
8687
                    foreach ($users as $user) {
8688
                        $userList[] = $user['user_id'];
8689
                    }
8690
                }
8691
                if (in_array($loginAsUserId, $userList)) {
8692
                    return true;
8693
                }
8694
            } else {
8695
                if (api_is_drh() &&
8696
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8697
                ) {
8698
                    return true;
8699
                }
8700
            }
8701
        }
8702
8703
        return false;
8704
    };
8705
8706
    $loginAsStatusForSessionAdmins = [STUDENT];
8707
8708
    if (api_get_configuration_value('allow_session_admin_login_as_teacher')) {
8709
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8710
    }
8711
8712
    return api_is_platform_admin() ||
8713
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8714
        $isDrh();
8715
}
8716
8717
/**
8718
 * @return bool
8719
 */
8720
function api_is_allowed_in_course()
8721
{
8722
    if (api_is_platform_admin()) {
8723
        return true;
8724
    }
8725
8726
    return Session::read('is_allowed_in_course');
8727
}
8728
8729
/**
8730
 * Set the cookie to go directly to the course code $in_firstpage
8731
 * after login.
8732
 *
8733
 * @param string $value is the course code of the course to go
8734
 */
8735
function api_set_firstpage_parameter($value)
8736
{
8737
    setcookie('GotoCourse', $value);
8738
}
8739
8740
/**
8741
 * Delete the cookie to go directly to the course code $in_firstpage
8742
 * after login.
8743
 */
8744
function api_delete_firstpage_parameter()
8745
{
8746
    setcookie('GotoCourse', '', time() - 3600);
8747
}
8748
8749
/**
8750
 * @return bool if course_code for direct course access after login is set
8751
 */
8752
function exist_firstpage_parameter()
8753
{
8754
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8755
}
8756
8757
/**
8758
 * @return string return the course_code of the course where user login
8759
 */
8760
function api_get_firstpage_parameter()
8761
{
8762
    return $_COOKIE['GotoCourse'];
8763
}
8764
8765
/**
8766
 * Return true on https install.
8767
 *
8768
 * @return bool
8769
 */
8770
function api_is_https()
8771
{
8772
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! empty($_SERVER['HTTP_...ttps_forwarded_proto']), Probably Intended Meaning: ! empty($_SERVER['HTTP_X...tps_forwarded_proto']))
Loading history...
8773
        $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_configuration['force_https_forwarded_proto'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_configuration seems to never exist and therefore empty should always be true.
Loading history...
8774
    ) {
8775
        $isSecured = true;
8776
    } else {
8777
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8778
            $isSecured = true;
8779
        } else {
8780
            $isSecured = false;
8781
            // last chance
8782
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8783
                $isSecured = true;
8784
            }
8785
        }
8786
    }
8787
8788
    return $isSecured;
8789
}
8790
8791
/**
8792
 * Return protocol (http or https).
8793
 *
8794
 * @return string
8795
 */
8796
function api_get_protocol()
8797
{
8798
    return api_is_https() ? 'https' : 'http';
8799
}
8800
8801
/**
8802
 * Return a string where " are replaced with 2 '
8803
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8804
 * e.g. : alert("<?php get_lang('Message') ?>");
8805
 * and message contains character ".
8806
 *
8807
 * @param string $in_text
8808
 *
8809
 * @return string
8810
 */
8811
function convert_double_quote_to_single($in_text)
8812
{
8813
    return api_preg_replace('/"/', "''", $in_text);
8814
}
8815
8816
/**
8817
 * Get origin.
8818
 *
8819
 * @param string
8820
 *
8821
 * @return string
8822
 */
8823
function api_get_origin()
8824
{
8825
    return isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8826
}
8827
8828
/**
8829
 * Warns an user that the portal reach certain limit.
8830
 *
8831
 * @param string $limitName
8832
 */
8833
function api_warn_hosting_contact($limitName)
8834
{
8835
    $hostingParams = api_get_configuration_value(1);
8836
    $email = null;
8837
8838
    if (!empty($hostingParams)) {
8839
        if (isset($hostingParams['hosting_contact_mail'])) {
8840
            $email = $hostingParams['hosting_contact_mail'];
8841
        }
8842
    }
8843
8844
    if (!empty($email)) {
8845
        $subject = get_lang('HostingWarningReached');
8846
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8847
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8848
        if (isset($hostingParams[$limitName])) {
8849
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8850
        }
8851
        api_mail_html(null, $email, $subject, $body);
8852
    }
8853
}
8854
8855
/**
8856
 * Gets value of a variable from app/config/configuration.php
8857
 * Variables that are not set in the configuration.php file but set elsewhere:
8858
 * - virtual_css_theme_folder (vchamilo plugin)
8859
 * - access_url (global.inc.php)
8860
 * - apc/apc_prefix (global.inc.php).
8861
 *
8862
 * @param string $variable
8863
 *
8864
 * @return bool|mixed
8865
 */
8866
function api_get_configuration_value($variable)
8867
{
8868
    global $_configuration;
8869
    // Check the current url id, id = 1 by default
8870
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8871
8872
    $variable = trim($variable);
8873
8874
    // Check if variable exists
8875
    if (isset($_configuration[$variable])) {
8876
        if (is_array($_configuration[$variable])) {
8877
            // Check if it exists for the sub portal
8878
            if (array_key_exists($urlId, $_configuration[$variable])) {
8879
                return $_configuration[$variable][$urlId];
8880
            } else {
8881
                // Try to found element with id = 1 (master portal)
8882
                if (array_key_exists(1, $_configuration[$variable])) {
8883
                    return $_configuration[$variable][1];
8884
                }
8885
            }
8886
        }
8887
8888
        return $_configuration[$variable];
8889
    }
8890
8891
    return false;
8892
}
8893
8894
/**
8895
 * Retreives and returns a value in a hierarchical configuration array
8896
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
8897
 *
8898
 * @param string $path      the successive array keys, separated by the separator
8899
 * @param mixed  $default   value to be returned if not found, null by default
8900
 * @param string $separator '/' by default
8901
 * @param array  $array     the active configuration array by default
8902
 *
8903
 * @return mixed the found value or $default
8904
 */
8905
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
8906
{
8907
    $pos = strpos($path, $separator);
8908
    if (false === $pos) {
8909
        if (is_null($array)) {
8910
            return api_get_configuration_value($path);
8911
        }
8912
        if (is_array($array) && array_key_exists($path, $array)) {
8913
            return $array[$path];
8914
        }
8915
8916
        return $default;
8917
    }
8918
    $key = substr($path, 0, $pos);
8919
    if (is_null($array)) {
8920
        $newArray = api_get_configuration_value($key);
8921
    } elseif (is_array($array) && array_key_exists($key, $array)) {
8922
        $newArray = $array[$key];
8923
    } else {
8924
        return $default;
8925
    }
8926
    if (is_array($newArray)) {
8927
        $newPath = substr($path, $pos + 1);
8928
8929
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
8930
    }
8931
8932
    return $default;
8933
}
8934
8935
/**
8936
 * Retrieves and returns a value in a hierarchical configuration array
8937
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
8938
 *
8939
 * @param array  $array     the recursive array that contains the value to be returned (or not)
8940
 * @param string $path      the successive array keys, separated by the separator
8941
 * @param mixed  $default   the value to be returned if not found
8942
 * @param string $separator the separator substring
8943
 *
8944
 * @return mixed the found value or $default
8945
 */
8946
function api_array_sub_value($array, $path, $default = null, $separator = '/')
8947
{
8948
    $pos = strpos($path, $separator);
8949
    if (false === $pos) {
8950
        if (is_array($array) && array_key_exists($path, $array)) {
8951
            return $array[$path];
8952
        }
8953
8954
        return $default;
8955
    }
8956
    $key = substr($path, 0, $pos);
8957
    if (is_array($array) && array_key_exists($key, $array)) {
8958
        $newArray = $array[$key];
8959
    } else {
8960
        return $default;
8961
    }
8962
    if (is_array($newArray)) {
8963
        $newPath = substr($path, $pos + 1);
8964
8965
        return api_array_sub_value($newArray, $newPath, $default);
8966
    }
8967
8968
    return $default;
8969
}
8970
8971
/**
8972
 * Returns supported image extensions in the portal.
8973
 *
8974
 * @param bool $supportVectors Whether vector images should also be accepted or not
8975
 *
8976
 * @return array Supported image extensions in the portal
8977
 */
8978
function api_get_supported_image_extensions($supportVectors = true)
8979
{
8980
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8981
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8982
    if ($supportVectors) {
8983
        array_push($supportedImageExtensions, 'svg');
8984
    }
8985
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8986
        array_push($supportedImageExtensions, 'webp');
8987
    }
8988
8989
    return $supportedImageExtensions;
8990
}
8991
8992
/**
8993
 * This setting changes the registration status for the campus.
8994
 *
8995
 * @author Patrick Cool <[email protected]>, Ghent University
8996
 *
8997
 * @version August 2006
8998
 *
8999
 * @param bool $listCampus Whether we authorize
9000
 *
9001
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
9002
 */
9003
function api_register_campus($listCampus = true)
9004
{
9005
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
9006
9007
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
9008
    Database::query($sql);
9009
9010
    if (!$listCampus) {
9011
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
9012
        Database::query($sql);
9013
    }
9014
}
9015
9016
/**
9017
 * Checks whether current user is a student boss.
9018
 *
9019
 * @global array $_user
9020
 *
9021
 * @return bool
9022
 */
9023
function api_is_student_boss()
9024
{
9025
    $_user = api_get_user_info();
9026
9027
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
9028
}
9029
9030
/**
9031
 * Check whether the user type should be exclude.
9032
 * Such as invited or anonymous users.
9033
 *
9034
 * @param bool $checkDB Optional. Whether check the user status
9035
 * @param int  $userId  Options. The user id
9036
 *
9037
 * @return bool
9038
 */
9039
function api_is_excluded_user_type($checkDB = false, $userId = 0)
9040
{
9041
    if ($checkDB) {
9042
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
9043
9044
        if ($userId == 0) {
9045
            return true;
9046
        }
9047
9048
        $userInfo = api_get_user_info($userId);
9049
9050
        switch ($userInfo['status']) {
9051
            case INVITEE:
9052
            case ANONYMOUS:
9053
                return true;
9054
            default:
9055
                return false;
9056
        }
9057
    }
9058
9059
    $isInvited = api_is_invitee();
9060
    $isAnonymous = api_is_anonymous();
9061
9062
    if ($isInvited || $isAnonymous) {
9063
        return true;
9064
    }
9065
9066
    return false;
9067
}
9068
9069
/**
9070
 * Get the user status to ignore in reports.
9071
 *
9072
 * @param string $format Optional. The result type (array or string)
9073
 *
9074
 * @return array|string
9075
 */
9076
function api_get_users_status_ignored_in_reports($format = 'array')
9077
{
9078
    $excludedTypes = [
9079
        INVITEE,
9080
        ANONYMOUS,
9081
    ];
9082
9083
    if ($format == 'string') {
9084
        return implode(', ', $excludedTypes);
9085
    }
9086
9087
    return $excludedTypes;
9088
}
9089
9090
/**
9091
 * Set the Site Use Cookie Warning for 1 year.
9092
 */
9093
function api_set_site_use_cookie_warning_cookie()
9094
{
9095
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
9096
}
9097
9098
/**
9099
 * Return true if the Site Use Cookie Warning Cookie warning exists.
9100
 *
9101
 * @return bool
9102
 */
9103
function api_site_use_cookie_warning_cookie_exist()
9104
{
9105
    return isset($_COOKIE['ChamiloUsesCookies']);
9106
}
9107
9108
/**
9109
 * Given a number of seconds, format the time to show hours, minutes and seconds.
9110
 *
9111
 * @param int    $time         The time in seconds
9112
 * @param string $originFormat Optional. PHP o JS
9113
 *
9114
 * @return string (00h00'00")
9115
 */
9116
function api_format_time($time, $originFormat = 'php')
9117
{
9118
    $h = get_lang('h');
9119
    $hours = $time / 3600;
9120
    $mins = ($time % 3600) / 60;
9121
    $secs = ($time % 60);
9122
9123
    if ($time < 0) {
9124
        $hours = 0;
9125
        $mins = 0;
9126
        $secs = 0;
9127
    }
9128
9129
    if ($originFormat == 'js') {
9130
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
9131
    } else {
9132
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
9133
    }
9134
9135
    return $formattedTime;
9136
}
9137
9138
/**
9139
 * Create a new empty directory with index.html file.
9140
 *
9141
 * @param string $name            The new directory name
9142
 * @param string $parentDirectory Directory parent directory name
9143
 *
9144
 * @return bool Return true if the directory was create. Otherwise return false
9145
 */
9146
function api_create_protected_dir($name, $parentDirectory)
9147
{
9148
    $isCreated = false;
9149
9150
    if (!is_writable($parentDirectory)) {
9151
        return false;
9152
    }
9153
9154
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
9155
9156
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
9157
        $fp = fopen($fullPath.'/index.html', 'w');
9158
9159
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
9160
            if (fwrite($fp, '<html><head><title></title></head><body></body></html>')) {
9161
                $isCreated = true;
9162
            }
9163
        }
9164
9165
        fclose($fp);
9166
    }
9167
9168
    return $isCreated;
9169
}
9170
9171
/**
9172
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
9173
 * Sender name and email can be specified, if not specified
9174
 * name and email of the platform admin are used.
9175
 *
9176
 * @author Bert Vanderkimpen ICT&O UGent
9177
 * @author Yannick Warnier <[email protected]>
9178
 *
9179
 * @param string    name of recipient
9180
 * @param string    email of recipient
9181
 * @param string    email subject
9182
 * @param string    email body
9183
 * @param string    sender name
9184
 * @param string    sender e-mail
9185
 * @param array  $extra_headers        in form $headers = array($name => $value) to allow parsing
9186
 * @param array  $data_file            (path and filename)
9187
 * @param bool   $embedded_image       True for attaching a embedded file inside content html (optional)
9188
 * @param array  $additionalParameters
9189
 * @param string $sendErrorTo          If there's an error while sending the email, $sendErrorTo will receive a notification
9190
 *
9191
 * @return int true if mail was sent
9192
 *
9193
 * @see             PHPMailer.php
9194
 */
9195
function api_mail_html(
9196
    $recipient_name,
9197
    $recipient_email,
9198
    $subject,
9199
    $message,
9200
    $senderName = '',
9201
    $senderEmail = '',
9202
    $extra_headers = [],
9203
    $data_file = [],
9204
    $embedded_image = false,
9205
    $additionalParameters = [],
9206
    $sendErrorTo = ''
9207
) {
9208
    global $platform_email;
9209
9210
    if (true === api_get_configuration_value('disable_send_mail')) {
9211
        return true;
9212
    }
9213
9214
    $mail = new PHPMailer();
9215
    $mail->Mailer = $platform_email['SMTP_MAILER'];
9216
    $mail->Host = $platform_email['SMTP_HOST'];
9217
    $mail->Port = $platform_email['SMTP_PORT'];
9218
    $mail->CharSet = isset($platform_email['SMTP_CHARSET']) ? $platform_email['SMTP_CHARSET'] : 'UTF-8';
9219
    // Stay far below SMTP protocol 980 chars limit.
9220
    $mail->WordWrap = 200;
9221
9222
    if ($platform_email['SMTP_AUTH']) {
9223
        $mail->SMTPAuth = 1;
9224
        $mail->Username = $platform_email['SMTP_USER'];
9225
        $mail->Password = $platform_email['SMTP_PASS'];
9226
        if (isset($platform_email['SMTP_SECURE'])) {
9227
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
9228
        }
9229
    }
9230
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
9231
9232
    // 5 = low, 1 = high
9233
    $mail->Priority = 3;
9234
    $mail->SMTPKeepAlive = true;
9235
9236
    api_set_noreply_and_from_address_to_mailer(
9237
        $mail,
9238
        ['name' => $senderName, 'email' => $senderEmail],
9239
        !empty($extra_headers['reply_to']) ? $extra_headers['reply_to'] : []
9240
    );
9241
9242
    if (!empty($sendErrorTo) && PHPMailer::ValidateAddress($sendErrorTo)) {
9243
        $mail->AddCustomHeader('Errors-To', $sendErrorTo);
9244
    }
9245
9246
    unset($extra_headers['reply_to']);
9247
9248
    $mail->Subject = $subject;
9249
    $mail->AltBody = strip_tags(
9250
        str_replace('<br />', "\n", api_html_entity_decode($message))
9251
    );
9252
9253
    $list = api_get_configuration_value('send_all_emails_to');
9254
    if (!empty($list) && isset($list['emails'])) {
9255
        foreach ($list['emails'] as $email) {
9256
            $mail->AddAddress($email);
9257
        }
9258
    }
9259
9260
    // Send embedded image.
9261
    if ($embedded_image) {
9262
        // Get all images html inside content.
9263
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
9264
        // Prepare new tag images.
9265
        $new_images_html = [];
9266
        $i = 1;
9267
        if (!empty($m[1])) {
9268
            foreach ($m[1] as $image_path) {
9269
                $real_path = realpath($image_path);
9270
                $filename = basename($image_path);
9271
                $image_cid = $filename.'_'.$i;
9272
                $encoding = 'base64';
9273
                $image_type = mime_content_type($real_path);
9274
                $mail->AddEmbeddedImage(
9275
                    $real_path,
9276
                    $image_cid,
9277
                    $filename,
9278
                    $encoding,
9279
                    $image_type
9280
                );
9281
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
9282
                $i++;
9283
            }
9284
        }
9285
9286
        // Replace origin image for new embedded image html.
9287
        $x = 0;
9288
        if (!empty($m[0])) {
9289
            foreach ($m[0] as $orig_img) {
9290
                $message = str_replace($orig_img, $new_images_html[$x], $message);
9291
                $x++;
9292
            }
9293
        }
9294
    }
9295
9296
    $mailView = new Template(null, false, false, false, false, false, false);
9297
9298
    $noReply = api_get_setting('noreply_email_address');
9299
    if (!empty($noReply)) {
9300
        $message .= '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
9301
    }
9302
    $mailView->assign('content', $message);
9303
9304
    if (isset($additionalParameters['link'])) {
9305
        $mailView->assign('link', $additionalParameters['link']);
9306
    }
9307
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
9308
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
9309
    $layout = $mailView->get_template('mail/mail.tpl');
9310
    $mail->Body = $mailView->fetch($layout);
9311
9312
    // Attachment.
9313
    if (!empty($data_file)) {
9314
        foreach ($data_file as $file_attach) {
9315
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
9316
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
9317
            }
9318
        }
9319
    }
9320
9321
    // Only valid addresses are accepted.
9322
    if (is_array($recipient_email)) {
9323
        foreach ($recipient_email as $dest) {
9324
            if (api_valid_email($dest)) {
9325
                $mail->AddAddress($dest, $recipient_name);
9326
            }
9327
        }
9328
    } else {
9329
        if (api_valid_email($recipient_email)) {
9330
            $mail->AddAddress($recipient_email, $recipient_name);
9331
        } else {
9332
            return 0;
9333
        }
9334
    }
9335
9336
    if (is_array($extra_headers) && count($extra_headers) > 0) {
9337
        foreach ($extra_headers as $key => $value) {
9338
            switch (strtolower($key)) {
9339
                case 'encoding':
9340
                case 'content-transfer-encoding':
9341
                    $mail->Encoding = $value;
9342
                    break;
9343
                case 'charset':
9344
                    $mail->CharSet = $value;
9345
                    break;
9346
                case 'contenttype':
9347
                case 'content-type':
9348
                    $mail->ContentType = $value;
9349
                    break;
9350
                default:
9351
                    $mail->AddCustomHeader($key, $value);
9352
                    break;
9353
            }
9354
        }
9355
    } else {
9356
        if (!empty($extra_headers)) {
9357
            $mail->AddCustomHeader($extra_headers);
9358
        }
9359
    }
9360
9361
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
9362
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
9363
9364
    if (!empty($platform_email['DKIM']) &&
9365
        !empty($platform_email['DKIM_SELECTOR']) &&
9366
        !empty($platform_email['DKIM_DOMAIN']) &&
9367
        (!empty($platform_email['DKIM_PRIVATE_KEY_STRING']) || !empty($platform_email['DKIM_PRIVATE_KEY']))) {
9368
        $mail->DKIM_selector = $platform_email['DKIM_SELECTOR'];
9369
        $mail->DKIM_domain = $platform_email['DKIM_DOMAIN'];
9370
        if (!empty($platform_email['SMTP_UNIQUE_SENDER'])) {
9371
            $mail->DKIM_identity = $platform_email['SMTP_FROM_EMAIL'];
9372
        }
9373
        $mail->DKIM_private_string = $platform_email['DKIM_PRIVATE_KEY_STRING'];
9374
        $mail->DKIM_private = $platform_email['DKIM_PRIVATE_KEY'];
9375
    }
9376
9377
    // Send the mail message.
9378
    if (!$mail->Send()) {
9379
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
9380
        if ($mail->SMTPDebug) {
9381
            error_log(
9382
                "Connection details :: ".
9383
                "Protocol: ".$mail->Mailer.' :: '.
9384
                "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
9385
                "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
9386
                ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
9387
                "Sender: ".$mail->Sender
9388
            );
9389
        }
9390
9391
        return 0;
9392
    }
9393
9394
    if (!empty($additionalParameters)) {
9395
        $plugin = new AppPlugin();
9396
        $smsPlugin = $plugin->getSMSPluginLibrary();
9397
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
9398
            $smsPlugin->send($additionalParameters);
9399
        }
9400
    }
9401
9402
    // Clear all the addresses.
9403
    $mail->ClearAddresses();
9404
9405
    // Clear all attachments
9406
    $mail->ClearAttachments();
9407
9408
    return 1;
9409
}
9410
9411
/**
9412
 * Checks access to a course group.
9413
 *
9414
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
9415
 * @param bool   $showHeader
9416
 */
9417
function api_protect_course_group($tool, $showHeader = true)
9418
{
9419
    $groupId = api_get_group_id();
9420
    if (!empty($groupId)) {
9421
        if (api_is_platform_admin()) {
9422
            return true;
9423
        }
9424
9425
        if (api_is_allowed_to_edit(false, true, true)) {
9426
            return true;
9427
        }
9428
9429
        $userId = api_get_user_id();
9430
        $sessionId = api_get_session_id();
9431
        if (!empty($sessionId)) {
9432
            if (api_is_coach($sessionId, api_get_course_int_id())) {
9433
                return true;
9434
            }
9435
9436
            if (api_is_drh()) {
9437
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
9438
                    return true;
9439
                }
9440
            }
9441
        }
9442
9443
        $groupInfo = GroupManager::get_group_properties($groupId);
9444
9445
        // Group doesn't exists
9446
        if (empty($groupInfo)) {
9447
            api_not_allowed($showHeader);
9448
        }
9449
9450
        // Check group access
9451
        $allow = GroupManager::user_has_access(
9452
            $userId,
9453
            $groupInfo['iid'],
9454
            $tool
9455
        );
9456
9457
        if (!$allow) {
9458
            api_not_allowed($showHeader);
9459
        }
9460
    }
9461
9462
    return false;
9463
}
9464
9465
/**
9466
 * Check if a date is in a date range.
9467
 *
9468
 * @param datetime $startDate
9469
 * @param datetime $endDate
9470
 * @param datetime $currentDate
9471
 *
9472
 * @return bool true if date is in rage, false otherwise
9473
 */
9474
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9475
{
9476
    $startDate = strtotime(api_get_local_time($startDate));
9477
    $endDate = strtotime(api_get_local_time($endDate));
9478
    $currentDate = strtotime(api_get_local_time($currentDate));
9479
9480
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9481
        return true;
9482
    }
9483
9484
    return false;
9485
}
9486
9487
/**
9488
 * Eliminate the duplicates of a multidimensional array by sending the key.
9489
 *
9490
 * @param array $array multidimensional array
9491
 * @param int   $key   key to find to compare
9492
 *
9493
 * @return array
9494
 */
9495
function api_unique_multidim_array($array, $key)
9496
{
9497
    $temp_array = [];
9498
    $i = 0;
9499
    $key_array = [];
9500
9501
    foreach ($array as $val) {
9502
        if (!in_array($val[$key], $key_array)) {
9503
            $key_array[$i] = $val[$key];
9504
            $temp_array[$i] = $val;
9505
        }
9506
        $i++;
9507
    }
9508
9509
    return $temp_array;
9510
}
9511
9512
/**
9513
 * Limit the access to Session Admins when the limit_session_admin_role
9514
 * configuration variable is set to true.
9515
 */
9516
function api_protect_limit_for_session_admin()
9517
{
9518
    $limitAdmin = api_get_setting('limit_session_admin_role');
9519
    if (api_is_session_admin() && $limitAdmin === 'true') {
9520
        api_not_allowed(true);
9521
    }
9522
}
9523
9524
/**
9525
 * Limits that a session admin has access to list users.
9526
 * When limit_session_admin_list_users configuration variable is set to true.
9527
 */
9528
function api_protect_session_admin_list_users()
9529
{
9530
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
9531
9532
    if (api_is_session_admin() && true === $limitAdmin) {
9533
        api_not_allowed(true);
9534
    }
9535
}
9536
9537
/**
9538
 * @return bool
9539
 */
9540
function api_is_student_view_active()
9541
{
9542
    $studentView = Session::read('studentview');
9543
9544
    return $studentView == 'studentview';
9545
}
9546
9547
/**
9548
 * Adds a file inside the upload/$type/id.
9549
 *
9550
 * @param string $type
9551
 * @param array  $file
9552
 * @param int    $itemId
9553
 * @param string $cropParameters
9554
 *
9555
 * @return array|bool
9556
 */
9557
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9558
{
9559
    $upload = process_uploaded_file($file);
9560
    if ($upload) {
9561
        $name = api_replace_dangerous_char($file['name']);
9562
9563
        // No "dangerous" files
9564
        $name = disable_dangerous_file($name);
9565
9566
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9567
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9568
9569
        if (!is_dir($path)) {
9570
            mkdir($path, api_get_permissions_for_new_directories(), true);
9571
        }
9572
9573
        $pathToSave = $path.$name;
9574
        $result = moveUploadedFile($file, $pathToSave);
9575
9576
        if ($result) {
9577
            if (!empty($cropParameters)) {
9578
                $image = new Image($pathToSave);
9579
                $image->crop($cropParameters);
9580
            }
9581
9582
            return ['path_to_save' => $pathId.$name];
9583
        }
9584
    }
9585
9586
    return false;
9587
}
9588
9589
/**
9590
 * @param string $type
9591
 * @param int    $itemId
9592
 * @param string $file
9593
 *
9594
 * @return bool
9595
 */
9596
function api_get_uploaded_web_url($type, $itemId, $file)
9597
{
9598
    return api_get_uploaded_file($type, $itemId, $file, true);
9599
}
9600
9601
/**
9602
 * @param string $type
9603
 * @param int    $itemId
9604
 * @param string $file
9605
 * @param bool   $getUrl
9606
 *
9607
 * @return bool
9608
 */
9609
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9610
{
9611
    $itemId = (int) $itemId;
9612
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9613
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9614
    $file = basename($file);
9615
    $file = $path.'/'.$file;
9616
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9617
        if ($getUrl) {
9618
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
9619
        }
9620
9621
        return $file;
9622
    }
9623
9624
    return false;
9625
}
9626
9627
/**
9628
 * @param string $type
9629
 * @param int    $itemId
9630
 * @param string $file
9631
 * @param string $title
9632
 */
9633
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9634
{
9635
    $file = api_get_uploaded_file($type, $itemId, $file);
9636
    if ($file) {
9637
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9638
            DocumentManager::file_send_for_download($file, true, $title);
9639
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
9640
        }
9641
    }
9642
    api_not_allowed(true);
9643
}
9644
9645
/**
9646
 * @param string $type
9647
 * @param string $file
9648
 */
9649
function api_remove_uploaded_file($type, $file)
9650
{
9651
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9652
    $path = $typePath.'/'.$file;
9653
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9654
        unlink($path);
9655
    }
9656
}
9657
9658
/**
9659
 * @param string $type
9660
 * @param int    $itemId
9661
 * @param string $file
9662
 *
9663
 * @return bool
9664
 */
9665
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9666
{
9667
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9668
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9669
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9670
        unlink($file);
9671
9672
        return true;
9673
    }
9674
9675
    return false;
9676
}
9677
9678
/**
9679
 * Converts string value to float value.
9680
 *
9681
 * 3.141516 => 3.141516
9682
 * 3,141516 => 3.141516
9683
 *
9684
 * @todo WIP
9685
 *
9686
 * @param string $number
9687
 *
9688
 * @return float
9689
 */
9690
function api_float_val($number)
9691
{
9692
    $number = (float) str_replace(',', '.', trim($number));
9693
9694
    return $number;
9695
}
9696
9697
/**
9698
 * Converts float values
9699
 * Example if $decimals = 2.
9700
 *
9701
 * 3.141516 => 3.14
9702
 * 3,141516 => 3,14
9703
 *
9704
 * @param string $number            number in iso code
9705
 * @param int    $decimals
9706
 * @param string $decimalSeparator
9707
 * @param string $thousandSeparator
9708
 *
9709
 * @return bool|string
9710
 */
9711
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9712
{
9713
    $number = api_float_val($number);
9714
9715
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9716
}
9717
9718
/**
9719
 * Set location url with a exit break by default.
9720
 *
9721
 * @param string $url
9722
 * @param bool   $exit
9723
 */
9724
function api_location($url, $exit = true)
9725
{
9726
    header('Location: '.$url);
9727
9728
    if ($exit) {
9729
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
9730
    }
9731
}
9732
9733
/**
9734
 * @return string
9735
 */
9736
function api_get_web_url()
9737
{
9738
    if (api_get_setting('server_type') === 'test') {
9739
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9740
    } else {
9741
        return api_get_path(WEB_PATH).'web/';
9742
    }
9743
}
9744
9745
/**
9746
 * @param string $from
9747
 * @param string $to
9748
 *
9749
 * @return string
9750
 */
9751
function api_get_relative_path($from, $to)
9752
{
9753
    // some compatibility fixes for Windows paths
9754
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9755
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9756
    $from = str_replace('\\', '/', $from);
9757
    $to = str_replace('\\', '/', $to);
9758
9759
    $from = explode('/', $from);
9760
    $to = explode('/', $to);
9761
    $relPath = $to;
9762
9763
    foreach ($from as $depth => $dir) {
9764
        // find first non-matching dir
9765
        if ($dir === $to[$depth]) {
9766
            // ignore this directory
9767
            array_shift($relPath);
9768
        } else {
9769
            // get number of remaining dirs to $from
9770
            $remaining = count($from) - $depth;
9771
            if ($remaining > 1) {
9772
                // add traversals up to first matching dir
9773
                $padLength = (count($relPath) + $remaining - 1) * -1;
9774
                $relPath = array_pad($relPath, $padLength, '..');
9775
                break;
9776
            } else {
9777
                $relPath[0] = './'.$relPath[0];
9778
            }
9779
        }
9780
    }
9781
9782
    return implode('/', $relPath);
9783
}
9784
9785
/**
9786
 * Unserialize content using Brummann\Polyfill\Unserialize.
9787
 *
9788
 * @param string $type
9789
 * @param string $serialized
9790
 *
9791
 * @return mixed
9792
 */
9793
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9794
{
9795
    switch ($type) {
9796
        case 'career':
9797
        case 'sequence_graph':
9798
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9799
            break;
9800
        case 'lp':
9801
            $allowedClasses = [
9802
                learnpath::class,
9803
                learnpathItem::class,
9804
                aicc::class,
9805
                aiccBlock::class,
9806
                aiccItem::class,
9807
                aiccObjective::class,
9808
                aiccResource::class,
9809
                scorm::class,
9810
                scormItem::class,
9811
                scormMetadata::class,
9812
                scormOrganization::class,
9813
                scormResource::class,
9814
                Link::class,
9815
                LpItem::class,
9816
            ];
9817
            break;
9818
        case 'course':
9819
            $allowedClasses = [
9820
                Course::class,
9821
                Announcement::class,
9822
                Attendance::class,
9823
                CalendarEvent::class,
9824
                CourseCopyLearnpath::class,
9825
                CourseCopyTestCategory::class,
9826
                CourseDescription::class,
9827
                CourseSession::class,
9828
                Document::class,
9829
                Forum::class,
9830
                ForumCategory::class,
9831
                ForumPost::class,
9832
                ForumTopic::class,
9833
                Glossary::class,
9834
                GradeBookBackup::class,
9835
                Link::class,
9836
                LinkCategory::class,
9837
                Quiz::class,
9838
                QuizQuestion::class,
9839
                QuizQuestionOption::class,
9840
                ScormDocument::class,
9841
                Survey::class,
9842
                SurveyInvitation::class,
9843
                SurveyQuestion::class,
9844
                Thematic::class,
9845
                ToolIntro::class,
9846
                Wiki::class,
9847
                Work::class,
9848
                stdClass::class,
9849
            ];
9850
            break;
9851
        case 'not_allowed_classes':
9852
        default:
9853
            $allowedClasses = false;
9854
    }
9855
9856
    if ($ignoreErrors) {
9857
        return @Unserialize::unserialize(
9858
            $serialized,
9859
            ['allowed_classes' => $allowedClasses]
9860
        );
9861
    }
9862
9863
    return Unserialize::unserialize(
9864
        $serialized,
9865
        ['allowed_classes' => $allowedClasses]
9866
    );
9867
}
9868
9869
/**
9870
 * Set the From and ReplyTo properties to PHPMailer instance.
9871
 *
9872
 * @throws \PHPMailer\PHPMailer\Exception
9873
 */
9874
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])
9875
{
9876
    $platformEmail = $GLOBALS['platform_email'];
9877
9878
    $noReplyAddress = api_get_setting('noreply_email_address');
9879
    $avoidReplyToAddress = false;
9880
9881
    if (!empty($noReplyAddress)) {
9882
        $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
9883
    }
9884
9885
    $notification = new Notification();
9886
    // If the parameter is set don't use the admin.
9887
    $senderName = !empty($sender['name']) ? $sender['name'] : $notification->getDefaultPlatformSenderName();
9888
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $notification->getDefaultPlatformSenderEmail();
9889
9890
    // Send errors to the platform admin
9891
    $adminEmail = api_get_setting('emailAdministrator');
9892
    if (PHPMailer::ValidateAddress($adminEmail)) {
9893
        $mailer->AddCustomHeader('Errors-To: '.$adminEmail);
9894
    }
9895
9896
    // Reply to first
9897
    if (!$avoidReplyToAddress) {
9898
        if (
9899
            !empty($replyToAddress) &&
9900
            PHPMailer::ValidateAddress($replyToAddress['mail'])
9901
        ) {
9902
            $mailer->AddReplyTo($replyToAddress['mail'], $replyToAddress['name']);
9903
            //$mailer->Sender = $replyToAddress['mail'];
9904
        }
9905
    }
9906
9907
    //If the SMTP configuration only accept one sender
9908
    if (
9909
        isset($platformEmail['SMTP_UNIQUE_SENDER']) &&
9910
        $platformEmail['SMTP_UNIQUE_SENDER']
9911
    ) {
9912
        $senderName = $notification->getDefaultPlatformSenderName();
9913
        $senderEmail = $notification->getDefaultPlatformSenderEmail();
9914
9915
        if (PHPMailer::ValidateAddress($senderEmail)) {
9916
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
9917
            $mailer->Sender = $senderEmail;
9918
        }
9919
    }
9920
9921
    $mailer->SetFrom($senderEmail, $senderName, !$avoidReplyToAddress);
9922
}
9923
9924
/**
9925
 * @param string $template
9926
 *
9927
 * @return string
9928
 */
9929
function api_find_template($template)
9930
{
9931
    return Template::findTemplateFilePath($template);
9932
}
9933
9934
/**
9935
 * Returns an array of languages (English names like "english", "french", etc)
9936
 * to ISO 639-1 codes (fr, es, etc) for use (for example) to show flags
9937
 * Note: 'english' is returned as 'gb'.
9938
 *
9939
 * @return array
9940
 */
9941
function api_get_language_list_for_flag()
9942
{
9943
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9944
    $sql = "SELECT english_name, isocode FROM $table
9945
            ORDER BY original_name ASC";
9946
    static $languages = [];
9947
    if (empty($languages)) {
9948
        $result = Database::query($sql);
9949
        while ($row = Database::fetch_array($result)) {
9950
            $languages[$row['english_name']] = $row['isocode'];
9951
        }
9952
        $languages['english'] = 'gb';
9953
    }
9954
9955
    return $languages;
9956
}
9957
9958
/**
9959
 * Generate the Javascript required for the on-page translation of
9960
 * multi-language strings.
9961
 *
9962
 * @throws Exception
9963
 *
9964
 * @return string
9965
 */
9966
function api_get_language_translate_html()
9967
{
9968
    $translate = api_get_configuration_value('translate_html');
9969
9970
    if (!$translate) {
9971
        return '';
9972
    }
9973
9974
    $languageList = api_get_languages();
9975
    $hideAll = '';
9976
    foreach ($languageList['all'] as $language) {
9977
        $hideAll .= '
9978
        $("span:lang('.$language['isocode'].')").filter(
9979
            function(e, val) {
9980
                // Only find the spans if they have set the lang
9981
                if ($(this).attr("lang") == null) {
9982
                    return false;
9983
                }
9984
9985
                // Ignore ckeditor classes
9986
                return !this.className.match(/cke(.*)/);
9987
        }).hide();'."\n";
9988
    }
9989
9990
    $userInfo = api_get_user_info();
9991
    $languageId = 0;
9992
    if (!empty($userInfo['language'])) {
9993
        $languageId = api_get_language_id($userInfo['language']);
9994
    } elseif (!empty($_GET['language'])) {
9995
        $languageId = api_get_language_id($_GET['language']);
9996
    }
9997
    $languageInfo = api_get_language_info($languageId);
9998
    $isoCode = 'en';
9999
10000
    if (!empty($languageInfo)) {
10001
        $isoCode = $languageInfo['isocode'];
10002
    }
10003
10004
    return '
10005
            $(function() {
10006
                '.$hideAll.'
10007
                var defaultLanguageFromUser = "'.$isoCode.'";
10008
10009
                $("span:lang('.$isoCode.')").filter(
10010
                    function() {
10011
                        // Ignore ckeditor classes
10012
                        return !this.className.match(/cke(.*)/);
10013
                }).show();
10014
10015
                var defaultLanguage = "";
10016
                var langFromUserFound = false;
10017
10018
                $(this).find("span").filter(
10019
                    function() {
10020
                        // Ignore ckeditor classes
10021
                        return !this.className.match(/cke(.*)/);
10022
                }).each(function() {
10023
                    defaultLanguage = $(this).attr("lang");
10024
                    if (defaultLanguage) {
10025
                        $(this).before().next("br").remove();
10026
                        if (defaultLanguageFromUser == defaultLanguage) {
10027
                            langFromUserFound = true;
10028
                        }
10029
                    }
10030
                });
10031
10032
                // Show default language
10033
                if (langFromUserFound == false && defaultLanguage) {
10034
                    $("span:lang("+defaultLanguage+")").filter(
10035
                    function() {
10036
                            // Ignore ckeditor classes
10037
                            return !this.className.match(/cke(.*)/);
10038
                    }).show();
10039
                }
10040
            });
10041
    ';
10042
}
10043
10044
/**
10045
 * Filter a multi-language HTML string (for the multi-language HTML
10046
 * feature) into the given language (strip the rest).
10047
 *
10048
 * @param string $htmlString The HTML string to "translate". Usually <p><span lang="en">Some string</span></p><p><span lang="fr">Une chaîne</span></p>
10049
 * @param string $language   The language in which we want to get the
10050
 *
10051
 * @throws Exception
10052
 *
10053
 * @return string The filtered string in the given language, or the full string if no translated string was identified
10054
 */
10055
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
10056
{
10057
    if (api_get_configuration_value('translate_html') != true) {
10058
        return $htmlString;
10059
    }
10060
    $userInfo = api_get_user_info();
10061
    $languageId = 0;
10062
    if (!empty($language)) {
10063
        $languageId = api_get_language_id($language);
10064
    } elseif (!empty($userInfo['language'])) {
10065
        $languageId = api_get_language_id($userInfo['language']);
10066
    }
10067
    $languageInfo = api_get_language_info($languageId);
10068
    $isoCode = 'en';
10069
10070
    if (!empty($languageInfo)) {
10071
        $isoCode = $languageInfo['isocode'];
10072
    }
10073
10074
    // Split HTML in the separate language strings
10075
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
10076
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
10077
        return $htmlString;
10078
    }
10079
    $matches = [];
10080
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
10081
    if (!empty($matches)) {
10082
        // matches[0] are the full string
10083
        // matches[1] are the languages
10084
        // matches[2] are the strings
10085
        foreach ($matches[1] as $id => $match) {
10086
            if ($match == $isoCode) {
10087
                return $matches[2][$id];
10088
            }
10089
        }
10090
        // Could find the pattern but could not find our language. Return the first language found.
10091
        return $matches[2][0];
10092
    }
10093
    // Could not find pattern. Just return the whole string. We shouldn't get here.
10094
    return $htmlString;
10095
}
10096