Passed
Push — 1.11.x ( fd1d83...fcb8bf )
by Julito
13:18
created

api_protect_webservices()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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

1277
                        /** @scrutinizer ignore-call */ 
1278
                        $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...
1278
                            api_get_user_id(),
1279
                            $initialData['exercise_id'],
1280
                            $course_info['real_id'],
1281
                            $session_id
1282
                        );
1283
                        if (empty($results)) {
1284
                            api_not_allowed($print_headers);
1285
1286
                            return false;
1287
                        }
1288
                    }
1289
                }
1290
            }
1291
        }
1292
    }
1293
1294
    api_block_inactive_user();
1295
1296
    return true;
1297
}
1298
1299
/**
1300
 * Function used to protect an admin script.
1301
 *
1302
 * The function blocks access when the user has no platform admin rights
1303
 * with an error message printed on default output
1304
 *
1305
 * @param bool Whether to allow session admins as well
1306
 * @param bool Whether to allow HR directors as well
1307
 * @param string An optional message (already passed through get_lang)
1308
 *
1309
 * @return bool True if user is allowed, false otherwise.
1310
 *              The function also outputs an error message in case not allowed
1311
 *
1312
 * @author Roan Embrechts (original author)
1313
 */
1314
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1315
{
1316
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1317
        api_not_allowed(true, $message);
1318
1319
        return false;
1320
    }
1321
1322
    api_block_inactive_user();
1323
1324
    return true;
1325
}
1326
1327
/**
1328
 * Blocks inactive users with a currently active session from accessing more pages "live".
1329
 *
1330
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1331
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1332
 */
1333
function api_block_inactive_user()
1334
{
1335
    $data = true;
1336
    if (api_get_configuration_value('security_block_inactive_users_immediately') != 1) {
1337
        return $data;
1338
    }
1339
1340
    $userId = api_get_user_id();
1341
    $homeUrl = api_get_path(WEB_PATH);
1342
    if ($userId == 0) {
1343
        return $data;
1344
    }
1345
1346
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1347
            WHERE id = $userId";
1348
1349
    $result = Database::query($sql);
1350
    if (Database::num_rows($result) > 0) {
1351
        $result_array = Database::fetch_array($result);
1352
        $data = (bool) $result_array['active'];
1353
    }
1354
    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...
1355
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1356
        $tpl->assign('hide_login_link', 1);
1357
1358
        //api_not_allowed(true, get_lang('AccountInactive'));
1359
        // we were not in a course, return to home page
1360
        $msg = Display::return_message(
1361
            get_lang('AccountInactive'),
1362
            'error',
1363
            false
1364
        );
1365
1366
        $msg .= '<p class="text-center">
1367
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1368
1369
        if (api_is_anonymous()) {
1370
            $form = api_get_not_allowed_login_form();
1371
            $msg .= '<div class="well">';
1372
            $msg .= $form->returnForm();
1373
            $msg .= '</div>';
1374
        }
1375
1376
        $tpl->assign('content', $msg);
1377
        $tpl->display_one_col_template();
1378
        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...
1379
    }
1380
1381
    return $data;
1382
}
1383
1384
/**
1385
 * Function used to protect a teacher script.
1386
 * The function blocks access when the user has no teacher rights.
1387
 *
1388
 * @return bool True if the current user can access the script, false otherwise
1389
 *
1390
 * @author Yoselyn Castillo
1391
 */
1392
function api_protect_teacher_script()
1393
{
1394
    if (!api_is_allowed_to_edit()) {
1395
        api_not_allowed(true);
1396
1397
        return false;
1398
    }
1399
1400
    return true;
1401
}
1402
1403
/**
1404
 * Function used to prevent anonymous users from accessing a script.
1405
 *
1406
 * @param bool|true $printHeaders
1407
 *
1408
 * @author Roan Embrechts
1409
 *
1410
 * @return bool
1411
 */
1412
function api_block_anonymous_users($printHeaders = true)
1413
{
1414
    $user = api_get_user_info();
1415
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1416
        api_not_allowed($printHeaders);
1417
1418
        return false;
1419
    }
1420
    api_block_inactive_user();
1421
1422
    return true;
1423
}
1424
1425
/**
1426
 * Returns a rough evaluation of the browser's name and version based on very
1427
 * simple regexp.
1428
 *
1429
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1430
 */
1431
function api_get_navigator()
1432
{
1433
    $navigator = 'Unknown';
1434
    $version = 0;
1435
1436
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1437
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1438
    }
1439
1440
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1441
        $navigator = 'Opera';
1442
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1443
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1444
        $navigator = 'Edge';
1445
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1446
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1447
        $navigator = 'Internet Explorer';
1448
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1449
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1450
        $navigator = 'Chrome';
1451
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1452
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1453
        $navigator = 'Safari';
1454
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1455
            // If this Safari does have the "Version/" string in its user agent
1456
            // then use that as a version indicator rather than what's after
1457
            // "Safari/" which is rather a "build number" or something
1458
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1459
        } else {
1460
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1461
        }
1462
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1463
        $navigator = 'Firefox';
1464
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1465
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1466
        $navigator = 'Netscape';
1467
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1468
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1469
        } else {
1470
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1471
        }
1472
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1473
        $navigator = 'Konqueror';
1474
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1475
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1476
        $navigator = 'AppleWebKit';
1477
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1478
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1479
        $navigator = 'Mozilla';
1480
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1481
    }
1482
1483
    // Now cut extra stuff around (mostly *after*) the version number
1484
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1485
1486
    if (strpos($version, '.') === false) {
1487
        $version = number_format(doubleval($version), 1);
1488
    }
1489
1490
    return ['name' => $navigator, 'version' => $version];
1491
}
1492
1493
/**
1494
 * @return true if user self registration is allowed, false otherwise
1495
 */
1496
function api_is_self_registration_allowed()
1497
{
1498
    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...
1499
}
1500
1501
/**
1502
 * This function returns the id of the user which is stored in the $_user array.
1503
 *
1504
 * example: The function can be used to check if a user is logged in
1505
 *          if (api_get_user_id())
1506
 *
1507
 * @return int the id of the current user, 0 if is empty
1508
 */
1509
function api_get_user_id()
1510
{
1511
    $userInfo = Session::read('_user');
1512
    if ($userInfo && isset($userInfo['user_id'])) {
1513
        return (int) $userInfo['user_id'];
1514
    }
1515
1516
    return 0;
1517
}
1518
1519
/**
1520
 * Gets the list of courses a specific user is subscribed to.
1521
 *
1522
 * @param int       User ID
1523
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1524
 *
1525
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1526
 *
1527
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1528
 */
1529
function api_get_user_courses($userId, $fetch_session = true)
1530
{
1531
    // Get out if not integer
1532
    if ($userId != strval(intval($userId))) {
1533
        return [];
1534
    }
1535
1536
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1537
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1538
1539
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1540
            FROM $t_course cc, $t_course_user cu
1541
            WHERE
1542
                cc.id = cu.c_id AND
1543
                cu.user_id = $userId AND
1544
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1545
    $result = Database::query($sql);
1546
    if ($result === false) {
1547
        return [];
1548
    }
1549
1550
    $courses = [];
1551
    while ($row = Database::fetch_array($result)) {
1552
        // we only need the database name of the course
1553
        $courses[] = $row;
1554
    }
1555
1556
    return $courses;
1557
}
1558
1559
/**
1560
 * Formats user information into a standard array
1561
 * This function should be only used inside api_get_user_info().
1562
 *
1563
 * @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...
1564
 * @param bool $add_password
1565
 * @param bool $loadAvatars  turn off to improve performance
1566
 *
1567
 * @return array Standard user array
1568
 */
1569
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1570
{
1571
    $result = [];
1572
1573
    $result['firstname'] = null;
1574
    $result['lastname'] = null;
1575
1576
    if (isset($user['firstname']) && isset($user['lastname'])) { // with only lowercase
1577
        $result['firstname'] = $user['firstname'];
1578
        $result['lastname'] = $user['lastname'];
1579
    } elseif (isset($user['firstName']) && isset($user['lastName'])) { // with uppercase letters
1580
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1581
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1582
    }
1583
1584
    if (isset($user['email'])) {
1585
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1586
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1587
    } else {
1588
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1589
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1590
    }
1591
1592
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1593
    $result['complete_name_with_username'] = $result['complete_name'];
1594
1595
    if (!empty($user['username']) && !api_get_configuration_value('hide_username_with_complete_name')) {
1596
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1597
    }
1598
1599
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1600
    if (!empty($user['email'])) {
1601
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1602
        if ($showEmail) {
1603
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1604
        }
1605
    } else {
1606
        $result['complete_name_with_email'] = $result['complete_name'];
1607
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1608
    }
1609
1610
    // Kept for historical reasons
1611
    $result['firstName'] = $result['firstname'];
1612
    $result['lastName'] = $result['lastname'];
1613
1614
    $attributes = [
1615
        'phone',
1616
        'address',
1617
        'picture_uri',
1618
        'official_code',
1619
        'status',
1620
        'active',
1621
        'auth_source',
1622
        'username',
1623
        'theme',
1624
        'language',
1625
        'creator_id',
1626
        'registration_date',
1627
        'hr_dept_id',
1628
        'expiration_date',
1629
        'last_login',
1630
        'user_is_online',
1631
    ];
1632
1633
    if (api_get_setting('extended_profile') === 'true') {
1634
        $attributes[] = 'competences';
1635
        $attributes[] = 'diplomas';
1636
        $attributes[] = 'teach';
1637
        $attributes[] = 'openarea';
1638
    }
1639
1640
    foreach ($attributes as $attribute) {
1641
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1642
    }
1643
1644
    $user_id = (int) $user['user_id'];
1645
    // Maintain the user_id index for backwards compatibility
1646
    $result['user_id'] = $result['id'] = $user_id;
1647
1648
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1649
    $result['has_certificates'] = 0;
1650
    if (!empty($hasCertificates)) {
1651
        $result['has_certificates'] = 1;
1652
    }
1653
1654
    $result['icon_status'] = '';
1655
    $result['icon_status_medium'] = '';
1656
1657
    $result['is_admin'] = UserManager::is_admin($user_id);
1658
1659
    // Getting user avatar.
1660
    if ($loadAvatars) {
1661
        $result['avatar'] = '';
1662
        $result['avatar_no_query'] = '';
1663
        $result['avatar_small'] = '';
1664
        $result['avatar_medium'] = '';
1665
1666
        if (!isset($user['avatar'])) {
1667
            $originalFile = UserManager::getUserPicture(
1668
                $user_id,
1669
                USER_IMAGE_SIZE_ORIGINAL,
1670
                null,
1671
                $result
1672
            );
1673
            $result['avatar'] = $originalFile;
1674
            $avatarString = explode('?', $result['avatar']);
1675
            $result['avatar_no_query'] = reset($avatarString);
1676
        } else {
1677
            $result['avatar'] = $user['avatar'];
1678
            $avatarString = explode('?', $user['avatar']);
1679
            $result['avatar_no_query'] = reset($avatarString);
1680
        }
1681
1682
        if (!isset($user['avatar_small'])) {
1683
            $smallFile = UserManager::getUserPicture(
1684
                $user_id,
1685
                USER_IMAGE_SIZE_SMALL,
1686
                null,
1687
                $result
1688
            );
1689
            $result['avatar_small'] = $smallFile;
1690
        } else {
1691
            $result['avatar_small'] = $user['avatar_small'];
1692
        }
1693
1694
        if (!isset($user['avatar_medium'])) {
1695
            $mediumFile = UserManager::getUserPicture(
1696
                $user_id,
1697
                USER_IMAGE_SIZE_MEDIUM,
1698
                null,
1699
                $result
1700
            );
1701
            $result['avatar_medium'] = $mediumFile;
1702
        } else {
1703
            $result['avatar_medium'] = $user['avatar_medium'];
1704
        }
1705
1706
        $urlImg = api_get_path(WEB_IMG_PATH);
1707
        $iconStatus = '';
1708
        $iconStatusMedium = '';
1709
        $label = '';
1710
        switch ($result['status']) {
1711
            case STUDENT:
1712
                if ($result['has_certificates']) {
1713
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1714
                    $label = get_lang('Graduated');
1715
                } else {
1716
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1717
                    $label = get_lang('Student');
1718
                }
1719
                break;
1720
            case COURSEMANAGER:
1721
                if ($result['is_admin']) {
1722
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1723
                    $label = get_lang('Admin');
1724
                } else {
1725
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1726
                    $label = get_lang('Teacher');
1727
                }
1728
                break;
1729
            case STUDENT_BOSS:
1730
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1731
                $label = get_lang('StudentBoss');
1732
                break;
1733
        }
1734
1735
        if (!empty($iconStatus)) {
1736
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1737
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1738
        }
1739
1740
        $result['icon_status'] = $iconStatus;
1741
        $result['icon_status_label'] = $label;
1742
        $result['icon_status_medium'] = $iconStatusMedium;
1743
    }
1744
1745
    if (isset($user['user_is_online'])) {
1746
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1747
    }
1748
    if (isset($user['user_is_online_in_chat'])) {
1749
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1750
    }
1751
1752
    if ($add_password) {
1753
        $result['password'] = $user['password'];
1754
    }
1755
1756
    if (isset($result['profile_completed'])) {
1757
        $result['profile_completed'] = $user['profile_completed'];
1758
    }
1759
1760
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1761
1762
    // Send message link
1763
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1764
    $result['complete_name_with_message_link'] = Display::url(
1765
        $result['complete_name_with_username'],
1766
        $sendMessage,
1767
        ['class' => 'ajax']
1768
    );
1769
1770
    if (isset($user['extra'])) {
1771
        $result['extra'] = $user['extra'];
1772
    }
1773
1774
    return $result;
1775
}
1776
1777
/**
1778
 * Finds all the information about a user.
1779
 * If no parameter is passed you find all the information about the current user.
1780
 *
1781
 * @param int  $user_id
1782
 * @param bool $checkIfUserOnline
1783
 * @param bool $showPassword
1784
 * @param bool $loadExtraData
1785
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1786
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1787
 * @param bool $updateCache              update apc cache if exists
1788
 *
1789
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1790
 *
1791
 * @author Patrick Cool <[email protected]>
1792
 * @author Julio Montoya
1793
 *
1794
 * @version 21 September 2004
1795
 */
1796
function api_get_user_info(
1797
    $user_id = 0,
1798
    $checkIfUserOnline = false,
1799
    $showPassword = false,
1800
    $loadExtraData = false,
1801
    $loadOnlyVisibleExtraData = false,
1802
    $loadAvatars = true,
1803
    $updateCache = false
1804
) {
1805
    $apcVar = null;
1806
    $user = false;
1807
    $cacheAvailable = api_get_configuration_value('apc');
1808
1809
    if (empty($user_id)) {
1810
        $userFromSession = Session::read('_user');
1811
1812
        if (isset($userFromSession)) {
1813
            if ($cacheAvailable === true &&
1814
                (
1815
                    empty($userFromSession['is_anonymous']) &&
1816
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1817
                )
1818
            ) {
1819
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1820
                if (apcu_exists($apcVar)) {
1821
                    if ($updateCache) {
1822
                        apcu_store($apcVar, $userFromSession, 60);
1823
                    }
1824
                    $user = apcu_fetch($apcVar);
1825
                } else {
1826
                    $user = _api_format_user(
1827
                        $userFromSession,
1828
                        $showPassword,
1829
                        $loadAvatars
1830
                    );
1831
                    apcu_store($apcVar, $user, 60);
1832
                }
1833
            } else {
1834
                $user = _api_format_user(
1835
                    $userFromSession,
1836
                    $showPassword,
1837
                    $loadAvatars
1838
                );
1839
            }
1840
1841
            return $user;
1842
        }
1843
1844
        return false;
1845
    }
1846
1847
    // Make sure user_id is safe
1848
    $user_id = (int) $user_id;
1849
1850
    // Re-use user information if not stale and already stored in APCu
1851
    if ($cacheAvailable === true) {
1852
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1853
        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...
1854
            $user = apcu_fetch($apcVar);
1855
1856
            return $user;
1857
        }
1858
    }
1859
1860
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1861
            WHERE id = $user_id";
1862
    $result = Database::query($sql);
1863
    if (Database::num_rows($result) > 0) {
1864
        $result_array = Database::fetch_array($result);
1865
        $result_array['user_is_online_in_chat'] = 0;
1866
        if ($checkIfUserOnline) {
1867
            $use_status_in_platform = user_is_online($user_id);
1868
            $result_array['user_is_online'] = $use_status_in_platform;
1869
            $user_online_in_chat = 0;
1870
            if ($use_status_in_platform) {
1871
                $user_status = UserManager::get_extra_user_data_by_field(
1872
                    $user_id,
1873
                    'user_chat_status',
1874
                    false,
1875
                    true
1876
                );
1877
                if ((int) $user_status['user_chat_status'] == 1) {
1878
                    $user_online_in_chat = 1;
1879
                }
1880
            }
1881
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1882
        }
1883
1884
        if ($loadExtraData) {
1885
            $fieldValue = new ExtraFieldValue('user');
1886
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1887
                $user_id,
1888
                $loadOnlyVisibleExtraData
1889
            );
1890
        }
1891
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1892
    }
1893
1894
    if ($cacheAvailable === true) {
1895
        apcu_store($apcVar, $user, 60);
1896
    }
1897
1898
    return $user;
1899
}
1900
1901
/**
1902
 * @param int $userId
1903
 *
1904
 * @return User
1905
 */
1906
function api_get_user_entity($userId)
1907
{
1908
    $userId = (int) $userId;
1909
    $repo = UserManager::getRepository();
1910
1911
    /** @var User $user */
1912
    $user = $repo->find($userId);
1913
1914
    return $user;
1915
}
1916
1917
/**
1918
 * Finds all the information about a user from username instead of user id.
1919
 *
1920
 * @param string $username
1921
 *
1922
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1923
 *
1924
 * @author Yannick Warnier <[email protected]>
1925
 */
1926
function api_get_user_info_from_username($username)
1927
{
1928
    if (empty($username)) {
1929
        return false;
1930
    }
1931
    $username = trim($username);
1932
1933
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1934
            WHERE username='".Database::escape_string($username)."'";
1935
    $result = Database::query($sql);
1936
    if (Database::num_rows($result) > 0) {
1937
        $resultArray = Database::fetch_array($result);
1938
1939
        return _api_format_user($resultArray);
1940
    }
1941
1942
    return false;
1943
}
1944
1945
/**
1946
 * Get first user with an email.
1947
 *
1948
 * @param string $email
1949
 *
1950
 * @return array|bool
1951
 */
1952
function api_get_user_info_from_email($email = '')
1953
{
1954
    if (empty($email)) {
1955
        return false;
1956
    }
1957
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1958
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1959
    $result = Database::query($sql);
1960
    if (Database::num_rows($result) > 0) {
1961
        $resultArray = Database::fetch_array($result);
1962
1963
        return _api_format_user($resultArray);
1964
    }
1965
1966
    return false;
1967
}
1968
1969
/**
1970
 * @return string
1971
 */
1972
function api_get_course_id()
1973
{
1974
    return Session::read('_cid', null);
1975
}
1976
1977
/**
1978
 * Returns the current course id (integer).
1979
 *
1980
 * @param string $code Optional course code
1981
 *
1982
 * @return int
1983
 */
1984
function api_get_course_int_id($code = null)
1985
{
1986
    if (!empty($code)) {
1987
        $code = Database::escape_string($code);
1988
        $row = Database::select(
1989
            'id',
1990
            Database::get_main_table(TABLE_MAIN_COURSE),
1991
            ['where' => ['code = ?' => [$code]]],
1992
            'first'
1993
        );
1994
1995
        if (is_array($row) && isset($row['id'])) {
1996
            return $row['id'];
1997
        } else {
1998
            return false;
1999
        }
2000
    }
2001
2002
    return Session::read('_real_cid', 0);
2003
}
2004
2005
/**
2006
 * Returns the current course directory.
2007
 *
2008
 * This function relies on api_get_course_info()
2009
 *
2010
 * @param string    The course code - optional (takes it from session if not given)
2011
 *
2012
 * @return string The directory where the course is located inside the Chamilo "courses" directory
2013
 *
2014
 * @author Yannick Warnier <[email protected]>
2015
 */
2016
function api_get_course_path($course_code = null)
2017
{
2018
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
2019
2020
    return $info['path'];
2021
}
2022
2023
/**
2024
 * Gets a course setting from the current course_setting table. Try always using integer values.
2025
 *
2026
 * @param string $settingName The name of the setting we want from the table
2027
 * @param array  $courseInfo
2028
 * @param bool   $force       force checking the value in the database
2029
 *
2030
 * @return mixed The value of that setting in that table. Return -1 if not found.
2031
 */
2032
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
2033
{
2034
    if (empty($courseInfo)) {
2035
        $courseInfo = api_get_course_info();
2036
    }
2037
2038
    if (empty($courseInfo) || empty($settingName)) {
2039
        return -1;
2040
    }
2041
2042
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2043
2044
    if (empty($courseId)) {
2045
        return -1;
2046
    }
2047
2048
    static $courseSettingInfo = [];
2049
2050
    if ($force) {
2051
        $courseSettingInfo = [];
2052
    }
2053
2054
    if (!isset($courseSettingInfo[$courseId])) {
2055
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2056
        $settingName = Database::escape_string($settingName);
2057
2058
        $sql = "SELECT variable, value FROM $table
2059
                WHERE c_id = $courseId ";
2060
        $res = Database::query($sql);
2061
        if (Database::num_rows($res) > 0) {
2062
            $result = Database::store_result($res, 'ASSOC');
2063
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2064
2065
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2066
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2067
                if (!is_null($value)) {
2068
                    $result = explode(',', $value);
2069
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2070
                }
2071
            }
2072
        }
2073
    }
2074
2075
    if (isset($courseSettingInfo[$courseId]) && array_key_exists($settingName, $courseSettingInfo[$courseId])) {
2076
        return $courseSettingInfo[$courseId][$settingName];
2077
    }
2078
2079
    return -1;
2080
}
2081
2082
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2083
{
2084
    $value = api_get_course_setting($settingName, $courseInfo, true);
2085
2086
    if (-1 === $value) {
2087
        // Check global settings
2088
        $value = api_get_plugin_setting($plugin, $settingName);
2089
        if ($value === 'true') {
2090
            return 1;
2091
        }
2092
        if ($value === 'false') {
2093
            return 0;
2094
        }
2095
        if (null === $value) {
2096
            return -1;
2097
        }
2098
    }
2099
2100
    return $value;
2101
}
2102
2103
/**
2104
 * Gets an anonymous user ID.
2105
 *
2106
 * For some tools that need tracking, like the learnpath tool, it is necessary
2107
 * to have a usable user-id to enable some kind of tracking, even if not
2108
 * perfect. An anonymous ID is taken from the users table by looking for a
2109
 * status of "6" (anonymous).
2110
 *
2111
 * @return int User ID of the anonymous user, or O if no anonymous user found
2112
 */
2113
function api_get_anonymous_id()
2114
{
2115
    // Find if another anon is connected now
2116
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2117
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2118
    $ip = Database::escape_string(api_get_real_ip());
2119
    $max = (int) api_get_configuration_value('max_anonymous_users');
2120
    if ($max >= 2) {
2121
        $sql = "SELECT * FROM $table as TEL
2122
                JOIN $tableU as U
2123
                ON U.user_id = TEL.login_user_id
2124
                WHERE TEL.user_ip = '$ip'
2125
                    AND U.status = ".ANONYMOUS."
2126
                    AND U.user_id != 2 ";
2127
2128
        $result = Database::query($sql);
2129
        if (empty(Database::num_rows($result))) {
2130
            $login = uniqid('anon_');
2131
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2132
            if (count($anonList) >= $max) {
2133
                foreach ($anonList as $userToDelete) {
2134
                    UserManager::delete_user($userToDelete['user_id']);
2135
                    break;
2136
                }
2137
            }
2138
            // Return the user ID
2139
            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...
2140
                $login,
2141
                'anon',
2142
                ANONYMOUS,
2143
                ' anonymous@localhost',
2144
                $login,
2145
                $login
2146
            );
2147
        } else {
2148
            $row = Database::fetch_array($result, 'ASSOC');
2149
2150
            return $row['user_id'];
2151
        }
2152
    }
2153
2154
    $table = Database::get_main_table(TABLE_MAIN_USER);
2155
    $sql = "SELECT user_id
2156
            FROM $table
2157
            WHERE status = ".ANONYMOUS." ";
2158
    $res = Database::query($sql);
2159
    if (Database::num_rows($res) > 0) {
2160
        $row = Database::fetch_array($res, 'ASSOC');
2161
2162
        return $row['user_id'];
2163
    }
2164
2165
    // No anonymous user was found.
2166
    return 0;
2167
}
2168
2169
/**
2170
 * @param string $courseCode
2171
 * @param int    $sessionId
2172
 * @param int    $groupId
2173
 *
2174
 * @return string
2175
 */
2176
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
2177
{
2178
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
2179
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2180
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2181
2182
    $url = 'cidReq='.$courseCode;
2183
    $url .= '&id_session='.$sessionId;
2184
    $url .= '&gidReq='.$groupId;
2185
2186
    return $url;
2187
}
2188
2189
/**
2190
 * Returns the current course url part including session, group, and gradebook params.
2191
 *
2192
 * @param bool   $addSessionId
2193
 * @param bool   $addGroupId
2194
 * @param string $origin
2195
 *
2196
 * @return string Course & session references to add to a URL
2197
 */
2198
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2199
{
2200
    $courseCode = api_get_course_id();
2201
    $url = empty($courseCode) ? '' : 'cidReq='.urlencode(htmlspecialchars($courseCode));
2202
    $origin = empty($origin) ? api_get_origin() : urlencode(Security::remove_XSS($origin));
2203
2204
    if ($addSessionId) {
2205
        if (!empty($url)) {
2206
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
2207
        }
2208
    }
2209
2210
    if ($addGroupId) {
2211
        if (!empty($url)) {
2212
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
2213
        }
2214
    }
2215
2216
    if (!empty($url)) {
2217
        $url .= '&gradebook='.intval(api_is_in_gradebook());
2218
        $url .= '&origin='.$origin;
2219
    }
2220
2221
    return $url;
2222
}
2223
2224
/**
2225
 * Get if we visited a gradebook page.
2226
 *
2227
 * @return bool
2228
 */
2229
function api_is_in_gradebook()
2230
{
2231
    return Session::read('in_gradebook', false);
2232
}
2233
2234
/**
2235
 * Set that we are in a page inside a gradebook.
2236
 */
2237
function api_set_in_gradebook()
2238
{
2239
    Session::write('in_gradebook', true);
2240
}
2241
2242
/**
2243
 * Remove gradebook session.
2244
 */
2245
function api_remove_in_gradebook()
2246
{
2247
    Session::erase('in_gradebook');
2248
}
2249
2250
/**
2251
 * Returns the current course info array see api_format_course_array()
2252
 * If the course_code is given, the returned array gives info about that
2253
 * particular course, if none given it gets the course info from the session.
2254
 *
2255
 * @param string $course_code
2256
 *
2257
 * @return array
2258
 */
2259
function api_get_course_info($course_code = null)
2260
{
2261
    if (!empty($course_code)) {
2262
        $course_code = Database::escape_string($course_code);
2263
        $courseId = api_get_course_int_id($course_code);
2264
2265
        if (empty($courseId)) {
2266
            return [];
2267
        }
2268
2269
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2270
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2271
        $sql = "SELECT
2272
                    course.*,
2273
                    course_category.code faCode,
2274
                    course_category.name faName
2275
                FROM $course_table
2276
                LEFT JOIN $course_cat_table
2277
                ON course.category_code = course_category.code
2278
                WHERE course.id = $courseId";
2279
        $result = Database::query($sql);
2280
        $courseInfo = [];
2281
        if (Database::num_rows($result) > 0) {
2282
            $data = Database::fetch_array($result);
2283
            $courseInfo = api_format_course_array($data);
2284
        }
2285
2286
        return $courseInfo;
2287
    }
2288
2289
    global $_course;
2290
    if ($_course == '-1') {
2291
        $_course = [];
2292
    }
2293
2294
    return $_course;
2295
}
2296
2297
/**
2298
 * @param int $courseId
2299
 *
2300
 * @return \Chamilo\CoreBundle\Entity\Course
2301
 */
2302
function api_get_course_entity($courseId = 0)
2303
{
2304
    if (empty($courseId)) {
2305
        $courseId = api_get_course_int_id();
2306
    }
2307
2308
    return Database::getManager()->getRepository('ChamiloCoreBundle:Course')->find($courseId);
2309
}
2310
2311
function api_get_group_entity($id = 0)
2312
{
2313
    if (empty($id)) {
2314
        $id = api_get_group_id();
2315
    }
2316
2317
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
2318
}
2319
2320
/**
2321
 * @param int $id
2322
 *
2323
 * @return \Chamilo\CoreBundle\Entity\Session
2324
 */
2325
function api_get_session_entity($id = 0)
2326
{
2327
    if (empty($id)) {
2328
        $id = api_get_session_id();
2329
    }
2330
2331
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2332
}
2333
2334
/**
2335
 * Returns the current course info array.
2336
2337
 * Now if the course_code is given, the returned array gives info about that
2338
 * particular course, not specially the current one.
2339
 *
2340
 * @param int $id Numeric ID of the course
2341
 *
2342
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2343
 */
2344
function api_get_course_info_by_id($id = null)
2345
{
2346
    if (!empty($id)) {
2347
        $id = (int) $id;
2348
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2349
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2350
        $sql = "SELECT
2351
                    course.*,
2352
                    course_category.code faCode,
2353
                    course_category.name faName
2354
                FROM $course_table
2355
                LEFT JOIN $course_cat_table
2356
                ON course.category_code = course_category.code
2357
                WHERE course.id = $id";
2358
        $result = Database::query($sql);
2359
        $_course = [];
2360
        if (Database::num_rows($result) > 0) {
2361
            $row = Database::fetch_array($result);
2362
            $_course = api_format_course_array($row);
2363
        }
2364
2365
        return $_course;
2366
    }
2367
2368
    global $_course;
2369
    if ($_course == '-1') {
2370
        $_course = [];
2371
    }
2372
2373
    return $_course;
2374
}
2375
2376
/**
2377
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2378
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
2379
 * now possibly causing massive confusion as a new "id" field has been added to
2380
 * the course table in 1.9.0.
2381
 *
2382
 * @param $course_data
2383
 *
2384
 * @return array
2385
 *
2386
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2387
 */
2388
function api_format_course_array($course_data)
2389
{
2390
    if (empty($course_data)) {
2391
        return [];
2392
    }
2393
2394
    $_course = [];
2395
    $_course['id'] = $course_data['code'];
2396
    $_course['real_id'] = $course_data['id'];
2397
2398
    // Added
2399
    $_course['code'] = $course_data['code'];
2400
    $_course['name'] = $course_data['title'];
2401
    $_course['title'] = $course_data['title'];
2402
    $_course['official_code'] = $course_data['visual_code'];
2403
    $_course['visual_code'] = $course_data['visual_code'];
2404
    $_course['sysCode'] = $course_data['code'];
2405
    $_course['path'] = $course_data['directory']; // Use as key in path.
2406
    $_course['directory'] = $course_data['directory'];
2407
    $_course['creation_date'] = $course_data['creation_date'];
2408
    $_course['titular'] = $course_data['tutor_name'];
2409
    $_course['tutor_name'] = $course_data['tutor_name'];
2410
    $_course['language'] = $course_data['course_language'];
2411
    $_course['extLink']['url'] = $course_data['department_url'];
2412
    $_course['extLink']['name'] = $course_data['department_name'];
2413
    $_course['categoryCode'] = $course_data['faCode'];
2414
    $_course['category_code'] = $course_data['faCode'];
2415
    $_course['categoryName'] = $course_data['faName'];
2416
    $_course['visibility'] = $course_data['visibility'];
2417
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2418
    $_course['subscribe'] = $course_data['subscribe'];
2419
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2420
    $_course['course_language'] = $course_data['course_language'];
2421
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2422
    $_course['legal'] = $course_data['legal'];
2423
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2424
    $_course['department_name'] = $course_data['department_name'];
2425
    $_course['department_url'] = $course_data['department_url'];
2426
2427
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2428
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2429
2430
    // Course password
2431
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2432
    $_course['disk_quota'] = $course_data['disk_quota'];
2433
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2434
    $_course['course_sys_path'] = $courseSys.'/';
2435
2436
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2437
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2438
    }
2439
2440
    // Course image
2441
    $_course['course_image_source'] = '';
2442
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2443
        $url_image = $webCourseHome.'/course-pic85x85.png';
2444
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2445
    } else {
2446
        $url_image = Display::return_icon(
2447
            'course.png',
2448
            null,
2449
            null,
2450
            ICON_SIZE_LARGE,
2451
            null,
2452
            true,
2453
            true
2454
        );
2455
    }
2456
    $_course['course_image'] = $url_image;
2457
2458
    // Course large image
2459
    $_course['course_image_large_source'] = '';
2460
    if (file_exists($courseSys.'/course-pic.png')) {
2461
        $url_image = $webCourseHome.'/course-pic.png';
2462
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2463
    } else {
2464
        $url_image = Display::return_icon(
2465
            'session_default.png',
2466
            null,
2467
            null,
2468
            null,
2469
            null,
2470
            true,
2471
            true
2472
        );
2473
    }
2474
2475
    $_course['course_image_large'] = $url_image;
2476
2477
    return $_course;
2478
}
2479
2480
/**
2481
 * Returns a difficult to guess password.
2482
 *
2483
 * @param int $length the length of the password
2484
 *
2485
 * @return string the generated password
2486
 */
2487
function api_generate_password($length = 8)
2488
{
2489
    if ($length < 2) {
2490
        $length = 2;
2491
    }
2492
2493
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2494
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2495
    $minNumbers = 2;
2496
    $length = $length - $minNumbers;
2497
    $minLowerCase = round($length / 2);
2498
    $minUpperCase = $length - $minLowerCase;
2499
2500
    $password = '';
2501
    $passwordRequirements = api_get_configuration_value('password_requirements');
2502
2503
    $factory = new RandomLib\Factory();
2504
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2505
2506
    if (!empty($passwordRequirements)) {
2507
        $length = $passwordRequirements['min']['length'];
2508
        $minNumbers = $passwordRequirements['min']['numeric'];
2509
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2510
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2511
2512
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2513
        // Add the rest to fill the length requirement
2514
        if ($rest > 0) {
2515
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2516
        }
2517
    }
2518
2519
    // Min digits default 2
2520
    for ($i = 0; $i < $minNumbers; $i++) {
2521
        $password .= $generator->generateInt(2, 9);
2522
    }
2523
2524
    // Min lowercase
2525
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2526
2527
    // Min uppercase
2528
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2529
    $password = str_shuffle($password);
2530
2531
    return $password;
2532
}
2533
2534
/**
2535
 * Checks a password to see wether it is OK to use.
2536
 *
2537
 * @param string $password
2538
 *
2539
 * @return bool if the password is acceptable, false otherwise
2540
 *              Notes about what a password "OK to use" is:
2541
 *              1. The password should be at least 5 characters long.
2542
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2543
 *              3. The password should contain at least 3 letters.
2544
 *              4. It should contain at least 2 digits.
2545
 *              Settings will change if the configuration value is set: password_requirements
2546
 */
2547
function api_check_password($password)
2548
{
2549
    $passwordRequirements = Security::getPasswordRequirements();
2550
2551
    $minLength = $passwordRequirements['min']['length'];
2552
    $minNumbers = $passwordRequirements['min']['numeric'];
2553
    // Optional
2554
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2555
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2556
2557
    $minLetters = $minLowerCase + $minUpperCase;
2558
    $passwordLength = api_strlen($password);
2559
2560
    $conditions = [
2561
        'min_length' => $passwordLength >= $minLength,
2562
    ];
2563
2564
    $digits = 0;
2565
    $lowerCase = 0;
2566
    $upperCase = 0;
2567
2568
    for ($i = 0; $i < $passwordLength; $i++) {
2569
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2570
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2571
            $upperCase++;
2572
        }
2573
2574
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2575
            $lowerCase++;
2576
        }
2577
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2578
            $digits++;
2579
        }
2580
    }
2581
2582
    // Min number of digits
2583
    $conditions['min_numeric'] = $digits >= $minNumbers;
2584
2585
    if (!empty($minUpperCase)) {
2586
        // Uppercase
2587
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2588
    }
2589
2590
    if (!empty($minLowerCase)) {
2591
        // Lowercase
2592
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2593
    }
2594
2595
    // Min letters
2596
    $letters = $upperCase + $lowerCase;
2597
    $conditions['min_letters'] = $letters >= $minLetters;
2598
2599
    $isPasswordOk = true;
2600
    foreach ($conditions as $condition) {
2601
        if ($condition === false) {
2602
            $isPasswordOk = false;
2603
            break;
2604
        }
2605
    }
2606
2607
    if ($isPasswordOk === false) {
2608
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2609
        $output .= Security::getPasswordRequirementsToString($conditions);
2610
2611
        Display::addFlash(Display::return_message($output, 'warning', false));
2612
    }
2613
2614
    return $isPasswordOk;
2615
}
2616
2617
/**
2618
 * Clears the user ID from the session if it was the anonymous user. Generally
2619
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2620
 * in the wrong context.
2621
 * This function is to be used in conjunction with the api_set_anonymous()
2622
 * function to simulate the user existence in case of an anonymous visit.
2623
 *
2624
 * @param bool      database check switch - passed to api_is_anonymous()
2625
 *
2626
 * @return bool true if succesfully unregistered, false if not anonymous
2627
 */
2628
function api_clear_anonymous($db_check = false)
2629
{
2630
    global $_user;
2631
    if (isset($_user['user_id']) && api_is_anonymous($_user['user_id'], $db_check)) {
2632
        unset($_user['user_id']);
2633
        Session::erase('_uid');
2634
2635
        return true;
2636
    }
2637
2638
    return false;
2639
}
2640
2641
/**
2642
 * Returns the status string corresponding to the status code.
2643
 *
2644
 * @author Noel Dieschburg
2645
 *
2646
 * @param int $status_code The integer status code (usually in the form of a constant)
2647
 *
2648
 * @return string
2649
 */
2650
function get_status_from_code($status_code)
2651
{
2652
    switch ($status_code) {
2653
        case STUDENT:
2654
            return get_lang('Student', '');
2655
        case COURSEMANAGER:
2656
            return get_lang('Teacher', '');
2657
        case SESSIONADMIN:
2658
            return get_lang('SessionsAdmin', '');
2659
        case DRH:
2660
            return get_lang('Drh', '');
2661
        case ANONYMOUS:
2662
            return get_lang('Anonymous', '');
2663
        case PLATFORM_ADMIN:
2664
            return get_lang('Administrator', '');
2665
        case SESSION_COURSE_COACH:
2666
            return get_lang('SessionCourseCoach', '');
2667
        case SESSION_GENERAL_COACH:
2668
            return get_lang('SessionGeneralCoach', '');
2669
        case COURSE_TUTOR:
2670
            return get_lang('CourseAssistant', '');
2671
        case STUDENT_BOSS:
2672
            return get_lang('StudentBoss', '');
2673
        case INVITEE:
2674
            return get_lang('Invitee', '');
2675
    }
2676
2677
    return '';
2678
}
2679
2680
/**
2681
 * Sets the current user as anonymous if it hasn't been identified yet. This
2682
 * function should be used inside a tool only. The function api_clear_anonymous()
2683
 * acts in the opposite direction by clearing the anonymous user's data every
2684
 * time we get on a course homepage or on a neutral page (index, admin, my space).
2685
 *
2686
 * @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2687
 */
2688
function api_set_anonymous()
2689
{
2690
    global $_user;
2691
2692
    if (!empty($_user['user_id'])) {
2693
        return false;
2694
    }
2695
2696
    $user_id = api_get_anonymous_id();
2697
    if ($user_id == 0) {
2698
        return false;
2699
    }
2700
2701
    if (isset($_user['is_anonymous'])) {
2702
        return false;
2703
    }
2704
2705
    Session::erase('_user');
2706
    $_user['user_id'] = $user_id;
2707
    $_user['is_anonymous'] = true;
2708
    $GLOBALS['_user'] = $_user;
2709
    Session::write('_user', $_user);
2710
2711
    return true;
2712
}
2713
2714
/**
2715
 * Gets the current Chamilo (not PHP/cookie) session ID.
2716
 *
2717
 * @return int O if no active session, the session ID otherwise
2718
 */
2719
function api_get_session_id()
2720
{
2721
    return (int) Session::read('id_session', 0);
2722
}
2723
2724
/**
2725
 * Gets the current Chamilo (not social network) group ID.
2726
 *
2727
 * @return int O if no active group, the group id otherwise
2728
 */
2729
function api_get_group_id()
2730
{
2731
    return (int) Session::read('_gid', 0);
2732
}
2733
2734
/**
2735
 * Gets the current or given session name.
2736
 *
2737
 * @param   int     Session ID (optional)
2738
 *
2739
 * @return string The session name, or null if not found
2740
 */
2741
function api_get_session_name($session_id = 0)
2742
{
2743
    if (empty($session_id)) {
2744
        $session_id = api_get_session_id();
2745
        if (empty($session_id)) {
2746
            return null;
2747
        }
2748
    }
2749
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2750
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2751
    $r = Database::query($s);
2752
    $c = Database::num_rows($r);
2753
    if ($c > 0) {
2754
        //technically, there can be only one, but anyway we take the first
2755
        $rec = Database::fetch_array($r);
2756
2757
        return $rec['name'];
2758
    }
2759
2760
    return null;
2761
}
2762
2763
/**
2764
 * Gets the session info by id.
2765
 *
2766
 * @param int $id Session ID
2767
 *
2768
 * @return array information of the session
2769
 */
2770
function api_get_session_info($id)
2771
{
2772
    return SessionManager::fetch($id);
2773
}
2774
2775
/**
2776
 * Gets the session visibility by session id.
2777
 *
2778
 * @param int  $session_id
2779
 * @param int  $courseId
2780
 * @param bool $ignore_visibility_for_admins
2781
 *
2782
 * @return int
2783
 *             0 = session still available,
2784
 *             SESSION_VISIBLE_READ_ONLY = 1,
2785
 *             SESSION_VISIBLE = 2,
2786
 *             SESSION_INVISIBLE = 3
2787
 */
2788
function api_get_session_visibility(
2789
    $session_id,
2790
    $courseId = null,
2791
    $ignore_visibility_for_admins = true,
2792
    $userId = 0
2793
) {
2794
    if (api_is_platform_admin()) {
2795
        if ($ignore_visibility_for_admins) {
2796
            return SESSION_AVAILABLE;
2797
        }
2798
    }
2799
2800
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2801
2802
    $now = time();
2803
    if (empty($session_id)) {
2804
        return 0; // Means that the session is still available.
2805
    }
2806
2807
    $session_id = (int) $session_id;
2808
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2809
2810
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2811
2812
    if (Database::num_rows($result) <= 0) {
2813
        return SESSION_INVISIBLE;
2814
    }
2815
2816
    $row = Database::fetch_array($result, 'ASSOC');
2817
    $visibility = $row['visibility'];
2818
2819
    // I don't care the session visibility.
2820
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2821
        // Session duration per student.
2822
        if (isset($row['duration']) && !empty($row['duration'])) {
2823
            $duration = $row['duration'] * 24 * 60 * 60;
2824
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2825
2826
            // If there is a session duration but there is no previous
2827
            // access by the user, then the session is still available
2828
            if (0 == count($courseAccess)) {
2829
                return SESSION_AVAILABLE;
2830
            }
2831
2832
            $currentTime = time();
2833
            $firstAccess = isset($courseAccess['login_course_date'])
2834
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2835
                : 0;
2836
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2837
            $userDuration = isset($userDurationData['duration'])
2838
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2839
                : 0;
2840
2841
            $totalDuration = $firstAccess + $duration + $userDuration;
2842
2843
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2844
        }
2845
2846
        return SESSION_AVAILABLE;
2847
    }
2848
2849
    // If start date was set.
2850
    if (!empty($row['access_start_date'])) {
2851
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2852
    }
2853
2854
    // If the end date was set.
2855
    if (!empty($row['access_end_date'])) {
2856
        // Only if date_start said that it was ok
2857
        if ($visibility === SESSION_AVAILABLE) {
2858
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2859
                ? SESSION_AVAILABLE // Date still available
2860
                : $row['visibility']; // Session ends
2861
        }
2862
    }
2863
2864
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2865
    $isCoach = api_is_coach($session_id, $courseId, $userId);
2866
2867
    if ($isCoach) {
2868
        // Test start date.
2869
        if (!empty($row['coach_access_start_date'])) {
2870
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2871
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2872
        }
2873
2874
        // Test end date.
2875
        if (!empty($row['coach_access_end_date'])) {
2876
            if ($visibility === SESSION_AVAILABLE) {
2877
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2878
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2879
            }
2880
        }
2881
    }
2882
2883
    return $visibility;
2884
}
2885
2886
/**
2887
 * This function returns a (star) session icon if the session is not null and
2888
 * the user is not a student.
2889
 *
2890
 * @param int $sessionId
2891
 * @param int $statusId  User status id - if 5 (student), will return empty
2892
 *
2893
 * @return string Session icon
2894
 */
2895
function api_get_session_image($sessionId, $statusId)
2896
{
2897
    $sessionId = (int) $sessionId;
2898
    $image = '';
2899
    if ($statusId != STUDENT) {
2900
        // Check whether is not a student
2901
        if ($sessionId > 0) {
2902
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2903
                'star.png',
2904
                get_lang('SessionSpecificResource'),
2905
                ['align' => 'absmiddle'],
2906
                ICON_SIZE_SMALL
2907
            );
2908
        }
2909
    }
2910
2911
    return $image;
2912
}
2913
2914
/**
2915
 * This function add an additional condition according to the session of the course.
2916
 *
2917
 * @param int    $session_id        session id
2918
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2919
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2920
 *                                  false for strict session condition
2921
 * @param string $session_field
2922
 *
2923
 * @return string condition of the session
2924
 */
2925
function api_get_session_condition(
2926
    $session_id,
2927
    $and = true,
2928
    $with_base_content = false,
2929
    $session_field = 'session_id'
2930
) {
2931
    $session_id = (int) $session_id;
2932
2933
    if (empty($session_field)) {
2934
        $session_field = 'session_id';
2935
    }
2936
    // Condition to show resources by session
2937
    $condition_add = $and ? ' AND ' : ' WHERE ';
2938
2939
    if ($with_base_content) {
2940
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2941
    } else {
2942
        if (empty($session_id)) {
2943
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2944
        } else {
2945
            $condition_session = $condition_add." $session_field = $session_id ";
2946
        }
2947
    }
2948
2949
    return $condition_session;
2950
}
2951
2952
/**
2953
 * Returns the value of a setting from the web-adjustable admin config settings.
2954
 *
2955
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2956
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2957
 * instead of
2958
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2959
 *
2960
 * @param string $variable The variable name
2961
 * @param string $key      The subkey (sub-variable) if any. Defaults to NULL
2962
 *
2963
 * @return string
2964
 *
2965
 * @author René Haentjens
2966
 * @author Bart Mollet
2967
 */
2968
function api_get_setting($variable, $key = null)
2969
{
2970
    global $_setting;
2971
    if ($variable == 'header_extra_content') {
2972
        $filename = api_get_home_path().'header_extra_content.txt';
2973
        if (file_exists($filename)) {
2974
            $value = file_get_contents($filename);
2975
2976
            return $value;
2977
        } else {
2978
            return '';
2979
        }
2980
    }
2981
    if ($variable == 'footer_extra_content') {
2982
        $filename = api_get_home_path().'footer_extra_content.txt';
2983
        if (file_exists($filename)) {
2984
            $value = file_get_contents($filename);
2985
2986
            return $value;
2987
        } else {
2988
            return '';
2989
        }
2990
    }
2991
    $value = null;
2992
    if (is_null($key)) {
2993
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
2994
    } else {
2995
        if (isset($_setting[$variable][$key])) {
2996
            $value = $_setting[$variable][$key];
2997
        }
2998
    }
2999
3000
    return $value;
3001
}
3002
3003
/**
3004
 * @param string $plugin
3005
 * @param string $variable
3006
 *
3007
 * @return string
3008
 */
3009
function api_get_plugin_setting($plugin, $variable)
3010
{
3011
    $variableName = $plugin.'_'.$variable;
3012
    $result = api_get_setting($variableName);
3013
3014
    if (isset($result[$plugin])) {
3015
        $value = $result[$plugin];
3016
        $unSerialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
3017
3018
        if (false !== $unSerialized) {
3019
            $value = $unSerialized;
3020
        }
3021
3022
        return $value;
3023
    }
3024
3025
    return null;
3026
}
3027
3028
/**
3029
 * Returns the value of a setting from the web-adjustable admin config settings.
3030
 */
3031
function api_get_settings_params($params)
3032
{
3033
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3034
3035
    return Database::select('*', $table, ['where' => $params]);
3036
}
3037
3038
/**
3039
 * @param array $params example: [id = ? => '1']
3040
 *
3041
 * @return array
3042
 */
3043
function api_get_settings_params_simple($params)
3044
{
3045
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3046
3047
    return Database::select('*', $table, ['where' => $params], 'one');
3048
}
3049
3050
/**
3051
 * Returns the value of a setting from the web-adjustable admin config settings.
3052
 */
3053
function api_delete_settings_params($params)
3054
{
3055
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3056
    $result = Database::delete($table, $params);
3057
3058
    return $result;
3059
}
3060
3061
/**
3062
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3063
 *
3064
 * @return string Escaped version of $_SERVER['PHP_SELF']
3065
 */
3066
function api_get_self()
3067
{
3068
    return htmlentities($_SERVER['PHP_SELF']);
3069
}
3070
3071
/* USER PERMISSIONS */
3072
3073
/**
3074
 * Checks whether current user is a platform administrator.
3075
 *
3076
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3077
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3078
 *
3079
 * @return bool true if the user has platform admin rights,
3080
 *              false otherwise
3081
 *
3082
 * @see usermanager::is_admin(user_id) for a user-id specific function
3083
 */
3084
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3085
{
3086
    $isAdmin = Session::read('is_platformAdmin');
3087
    if ($isAdmin) {
3088
        return true;
3089
    }
3090
    $user = api_get_user_info();
3091
3092
    return
3093
        isset($user['status']) &&
3094
        (
3095
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
3096
            ($allowDrh && $user['status'] == DRH)
3097
        );
3098
}
3099
3100
/**
3101
 * Checks whether the user given as user id is in the admin table.
3102
 *
3103
 * @param int $user_id If none provided, will use current user
3104
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3105
 *
3106
 * @return bool True if the user is admin, false otherwise
3107
 */
3108
function api_is_platform_admin_by_id($user_id = null, $url = null)
3109
{
3110
    $user_id = (int) $user_id;
3111
    if (empty($user_id)) {
3112
        $user_id = api_get_user_id();
3113
    }
3114
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3115
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3116
    $res = Database::query($sql);
3117
    $is_admin = Database::num_rows($res) === 1;
3118
    if (!$is_admin || !isset($url)) {
3119
        return $is_admin;
3120
    }
3121
    // We get here only if $url is set
3122
    $url = (int) $url;
3123
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3124
    $sql = "SELECT * FROM $url_user_table
3125
            WHERE access_url_id = $url AND user_id = $user_id";
3126
    $res = Database::query($sql);
3127
    $result = Database::num_rows($res) === 1;
3128
3129
    return $result;
3130
}
3131
3132
/**
3133
 * Returns the user's numeric status ID from the users table.
3134
 *
3135
 * @param int $user_id If none provided, will use current user
3136
 *
3137
 * @return int User's status (1 for teacher, 5 for student, etc)
3138
 */
3139
function api_get_user_status($user_id = null)
3140
{
3141
    $user_id = (int) $user_id;
3142
    if (empty($user_id)) {
3143
        $user_id = api_get_user_id();
3144
    }
3145
    $table = Database::get_main_table(TABLE_MAIN_USER);
3146
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3147
    $result = Database::query($sql);
3148
    $status = null;
3149
    if (Database::num_rows($result)) {
3150
        $row = Database::fetch_array($result);
3151
        $status = $row['status'];
3152
    }
3153
3154
    return $status;
3155
}
3156
3157
/**
3158
 * Checks whether current user is allowed to create courses.
3159
 *
3160
 * @return bool true if the user has course creation rights,
3161
 *              false otherwise
3162
 */
3163
function api_is_allowed_to_create_course()
3164
{
3165
    if (api_is_platform_admin()) {
3166
        return true;
3167
    }
3168
3169
    // Teachers can only create courses
3170
    if (api_is_teacher()) {
3171
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
3172
            return true;
3173
        } else {
3174
            return false;
3175
        }
3176
    }
3177
3178
    return Session::read('is_allowedCreateCourse');
3179
}
3180
3181
/**
3182
 * Checks whether the current user is a course administrator.
3183
 *
3184
 * @return bool True if current user is a course administrator
3185
 */
3186
function api_is_course_admin()
3187
{
3188
    if (api_is_platform_admin()) {
3189
        return true;
3190
    }
3191
3192
    return Session::read('is_courseAdmin');
3193
}
3194
3195
/**
3196
 * Checks whether the current user is a course coach
3197
 * Based on the presence of user in session.id_coach (session general coach).
3198
 *
3199
 * @return bool True if current user is a course coach
3200
 */
3201
function api_is_session_general_coach()
3202
{
3203
    return Session::read('is_session_general_coach');
3204
}
3205
3206
/**
3207
 * Checks whether the current user is a course tutor
3208
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3209
 *
3210
 * @return bool True if current user is a course tutor
3211
 */
3212
function api_is_course_tutor()
3213
{
3214
    return Session::read('is_courseTutor');
3215
}
3216
3217
/**
3218
 * @param int $user_id
3219
 * @param int $courseId
3220
 * @param int $session_id
3221
 *
3222
 * @return bool
3223
 */
3224
function api_is_course_session_coach($user_id, $courseId, $session_id)
3225
{
3226
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3227
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3228
3229
    $user_id = (int) $user_id;
3230
    $session_id = (int) $session_id;
3231
    $courseId = (int) $courseId;
3232
3233
    $sql = "SELECT DISTINCT session.id
3234
            FROM $session_table
3235
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3236
            ON session.id = session_rc_ru.session_id
3237
            WHERE
3238
                session_rc_ru.user_id = '".$user_id."'  AND
3239
                session_rc_ru.c_id = '$courseId' AND
3240
                session_rc_ru.status = 2 AND
3241
                session_rc_ru.session_id = '$session_id'";
3242
    $result = Database::query($sql);
3243
3244
    return Database::num_rows($result) > 0;
3245
}
3246
3247
/**
3248
 * Checks whether the current user is a course or session coach.
3249
 *
3250
 * @param int $session_id
3251
 * @param int $courseId
3252
 * @param bool  Check whether we are in student view and, if we are, return false
3253
 * @param int $userId
3254
 *
3255
 * @return bool True if current user is a course or session coach
3256
 */
3257
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
3258
{
3259
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
3260
3261
    if (!empty($session_id)) {
3262
        $session_id = (int) $session_id;
3263
    } else {
3264
        $session_id = api_get_session_id();
3265
    }
3266
3267
    // The student preview was on
3268
    if ($check_student_view && api_is_student_view_active()) {
3269
        return false;
3270
    }
3271
3272
    if (!empty($courseId)) {
3273
        $courseId = (int) $courseId;
3274
    } else {
3275
        $courseId = api_get_course_int_id();
3276
    }
3277
3278
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3279
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3280
    $sessionIsCoach = [];
3281
3282
    if (!empty($courseId)) {
3283
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3284
                FROM $session_table s
3285
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3286
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3287
                WHERE
3288
                    session_rc_ru.c_id = '$courseId' AND
3289
                    session_rc_ru.status = 2 AND
3290
                    session_rc_ru.session_id = '$session_id'";
3291
        $result = Database::query($sql);
3292
        $sessionIsCoach = Database::store_result($result);
3293
    }
3294
3295
    if (!empty($session_id)) {
3296
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3297
                FROM $session_table
3298
                WHERE session.id_coach = $userId AND id = $session_id
3299
                ORDER BY access_start_date, access_end_date, name";
3300
        $result = Database::query($sql);
3301
        if (!empty($sessionIsCoach)) {
3302
            $sessionIsCoach = array_merge(
3303
                $sessionIsCoach,
3304
                Database::store_result($result)
3305
            );
3306
        } else {
3307
            $sessionIsCoach = Database::store_result($result);
3308
        }
3309
    }
3310
3311
    return count($sessionIsCoach) > 0;
3312
}
3313
3314
/**
3315
 * Checks whether the current user is a session administrator.
3316
 *
3317
 * @return bool True if current user is a course administrator
3318
 */
3319
function api_is_session_admin()
3320
{
3321
    $user = api_get_user_info();
3322
3323
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
3324
}
3325
3326
/**
3327
 * Checks whether the current user is a human resources manager.
3328
 *
3329
 * @return bool True if current user is a human resources manager
3330
 */
3331
function api_is_drh()
3332
{
3333
    $user = api_get_user_info();
3334
3335
    return isset($user['status']) && $user['status'] == DRH;
3336
}
3337
3338
/**
3339
 * Checks whether the current user is a student.
3340
 *
3341
 * @return bool True if current user is a human resources manager
3342
 */
3343
function api_is_student()
3344
{
3345
    $user = api_get_user_info();
3346
3347
    return isset($user['status']) && $user['status'] == STUDENT;
3348
}
3349
3350
/**
3351
 * Checks whether the current user has the status 'teacher'.
3352
 *
3353
 * @return bool True if current user is a human resources manager
3354
 */
3355
function api_is_teacher()
3356
{
3357
    $user = api_get_user_info();
3358
3359
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
3360
}
3361
3362
/**
3363
 * Checks whether the current user is a invited user.
3364
 *
3365
 * @return bool
3366
 */
3367
function api_is_invitee()
3368
{
3369
    $user = api_get_user_info();
3370
3371
    return isset($user['status']) && $user['status'] == INVITEE;
3372
}
3373
3374
/**
3375
 * This function checks whether a session is assigned into a category.
3376
 *
3377
 * @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...
3378
 * @param string    - category name
3379
 *
3380
 * @return bool - true if is found, otherwise false
3381
 */
3382
function api_is_session_in_category($session_id, $category_name)
3383
{
3384
    $session_id = (int) $session_id;
3385
    $category_name = Database::escape_string($category_name);
3386
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3387
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3388
3389
    $sql = "SELECT 1
3390
            FROM $tbl_session
3391
            WHERE $session_id IN (
3392
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3393
                WHERE
3394
                  s.session_category_id = sc.id AND
3395
                  sc.name LIKE '%$category_name'
3396
            )";
3397
    $rs = Database::query($sql);
3398
3399
    if (Database::num_rows($rs) > 0) {
3400
        return true;
3401
    } else {
3402
        return false;
3403
    }
3404
}
3405
3406
/**
3407
 * Displays the title of a tool.
3408
 * Normal use: parameter is a string:
3409
 * api_display_tool_title("My Tool").
3410
 *
3411
 * Optionally, there can be a subtitle below
3412
 * the normal title, and / or a supra title above the normal title.
3413
 *
3414
 * e.g. supra title:
3415
 * group
3416
 * GROUP PROPERTIES
3417
 *
3418
 * e.g. subtitle:
3419
 * AGENDA
3420
 * calender & events tool
3421
 *
3422
 * @author Hugues Peeters <[email protected]>
3423
 *
3424
 * @param mixed $title_element - it could either be a string or an array
3425
 *                             containing 'supraTitle', 'mainTitle',
3426
 *                             'subTitle'
3427
 */
3428
function api_display_tool_title($title_element)
3429
{
3430
    if (is_string($title_element)) {
3431
        $tit = $title_element;
3432
        unset($title_element);
3433
        $title_element = [];
3434
        $title_element['mainTitle'] = $tit;
3435
    }
3436
    echo '<h3>';
3437
    if (!empty($title_element['supraTitle'])) {
3438
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3439
    }
3440
    if (!empty($title_element['mainTitle'])) {
3441
        echo $title_element['mainTitle'];
3442
    }
3443
    if (!empty($title_element['subTitle'])) {
3444
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3445
    }
3446
    echo '</h3>';
3447
}
3448
3449
/**
3450
 * Displays options for switching between student view and course manager view.
3451
 *
3452
 * Changes in version 1.2 (Patrick Cool)
3453
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3454
 * is changed explicitly
3455
 *
3456
 * Changes in version 1.1 (Patrick Cool)
3457
 * student view now works correctly in subfolders of the document tool
3458
 * student view works correctly in the new links tool
3459
 *
3460
 * Example code for using this in your tools:
3461
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3462
 * //   display_tool_view_option($isStudentView);
3463
 * //}
3464
 * //and in later sections, use api_is_allowed_to_edit()
3465
 *
3466
 * @author Roan Embrechts
3467
 * @author Patrick Cool
3468
 * @author Julio Montoya, changes added in Chamilo
3469
 *
3470
 * @version 1.2
3471
 *
3472
 * @todo rewrite code so it is easier to understand
3473
 */
3474
function api_display_tool_view_option()
3475
{
3476
    if (api_get_setting('student_view_enabled') != 'true') {
3477
        return '';
3478
    }
3479
3480
    $sourceurl = '';
3481
    $is_framed = false;
3482
    // Exceptions apply for all multi-frames pages
3483
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3484
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3485
        return '';
3486
    }
3487
3488
    // Uncomment to remove student view link from document view page
3489
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3490
        if (empty($_GET['lp_id'])) {
3491
            return '';
3492
        }
3493
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3494
        $sourceurl = str_replace(
3495
            'lp/lp_header.php',
3496
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3497
            $sourceurl
3498
        );
3499
        //showinframes doesn't handle student view anyway...
3500
        //return '';
3501
        $is_framed = true;
3502
    }
3503
3504
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3505
    if (!$is_framed) {
3506
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3507
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3508
        } else {
3509
            $sourceurl = $_SERVER['REQUEST_URI'];
3510
        }
3511
    }
3512
3513
    $output_string = '';
3514
    if (!empty($_SESSION['studentview'])) {
3515
        if ($_SESSION['studentview'] == 'studentview') {
3516
            // We have to remove the isStudentView=true from the $sourceurl
3517
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3518
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3519
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3520
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3521
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3522
            // Switching to teacherview
3523
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3524
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3525
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3526
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3527
        }
3528
    } else {
3529
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3530
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3531
    }
3532
    $output_string = Security::remove_XSS($output_string);
3533
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3534
3535
    return $html;
3536
}
3537
3538
// TODO: This is for the permission section.
3539
/**
3540
 * Function that removes the need to directly use is_courseAdmin global in
3541
 * tool scripts. It returns true or false depending on the user's rights in
3542
 * this particular course.
3543
 * Optionally checking for tutor and coach roles here allows us to use the
3544
 * student_view feature altogether with these roles as well.
3545
 *
3546
 * @param bool  Whether to check if the user has the tutor role
3547
 * @param bool  Whether to check if the user has the coach role
3548
 * @param bool  Whether to check if the user has the session coach role
3549
 * @param bool  check the student view or not
3550
 *
3551
 * @author Roan Embrechts
3552
 * @author Patrick Cool
3553
 * @author Julio Montoya
3554
 *
3555
 * @version 1.1, February 2004
3556
 *
3557
 * @return bool true: the user has the rights to edit, false: he does not
3558
 */
3559
function api_is_allowed_to_edit(
3560
    $tutor = false,
3561
    $coach = false,
3562
    $session_coach = false,
3563
    $check_student_view = true
3564
) {
3565
    $allowSessionAdminEdit = api_get_configuration_value('session_admins_edit_courses_content') === true;
3566
3567
    // Admins can edit anything.
3568
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3569
        //The student preview was on
3570
        if ($check_student_view && api_is_student_view_active()) {
3571
            return false;
3572
        }
3573
3574
        return true;
3575
    }
3576
3577
    $sessionId = api_get_session_id();
3578
3579
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3580
        $efv = new ExtraFieldValue('course');
3581
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3582
            api_get_course_int_id(),
3583
            'session_courses_read_only_mode'
3584
        );
3585
3586
        if (!empty($lockExrafieldField['value'])) {
3587
            return false;
3588
        }
3589
    }
3590
3591
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3592
    $session_visibility = api_get_session_visibility($sessionId);
3593
    $is_courseAdmin = api_is_course_admin();
3594
3595
    if (!$is_courseAdmin && $tutor) {
3596
        // If we also want to check if the user is a tutor...
3597
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3598
    }
3599
3600
    if (!$is_courseAdmin && $coach) {
3601
        // If we also want to check if the user is a coach...';
3602
        // Check if session visibility is read only for coaches.
3603
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3604
            $is_allowed_coach_to_edit = false;
3605
        }
3606
3607
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3608
            // Check if coach is allowed to edit a course.
3609
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3610
        }
3611
    }
3612
3613
    if (!$is_courseAdmin && $session_coach) {
3614
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3615
    }
3616
3617
    // Check if the student_view is enabled, and if so, if it is activated.
3618
    if (api_get_setting('student_view_enabled') == 'true') {
3619
        if (!empty($sessionId)) {
3620
            // Check if session visibility is read only for coaches.
3621
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3622
                $is_allowed_coach_to_edit = false;
3623
            }
3624
3625
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3626
                // Check if coach is allowed to edit a course.
3627
                $is_allowed = $is_allowed_coach_to_edit;
3628
            } else {
3629
                $is_allowed = false;
3630
            }
3631
            if ($check_student_view) {
3632
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3633
            }
3634
        } else {
3635
            if ($check_student_view) {
3636
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3637
            } else {
3638
                $is_allowed = $is_courseAdmin;
3639
            }
3640
        }
3641
3642
        return $is_allowed;
3643
    } else {
3644
        return $is_courseAdmin;
3645
    }
3646
}
3647
3648
/**
3649
 * Returns true if user is a course coach of at least one course in session.
3650
 *
3651
 * @param int $sessionId
3652
 *
3653
 * @return bool
3654
 */
3655
function api_is_coach_of_course_in_session($sessionId)
3656
{
3657
    if (api_is_platform_admin()) {
3658
        return true;
3659
    }
3660
3661
    $userId = api_get_user_id();
3662
    $courseList = UserManager::get_courses_list_by_session(
3663
        $userId,
3664
        $sessionId
3665
    );
3666
3667
    // Session visibility.
3668
    $visibility = api_get_session_visibility(
3669
        $sessionId,
3670
        null,
3671
        false
3672
    );
3673
3674
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3675
        // Course Coach session visibility.
3676
        $blockedCourseCount = 0;
3677
        $closedVisibilityList = [
3678
            COURSE_VISIBILITY_CLOSED,
3679
            COURSE_VISIBILITY_HIDDEN,
3680
        ];
3681
3682
        foreach ($courseList as $course) {
3683
            // Checking session visibility
3684
            $sessionCourseVisibility = api_get_session_visibility(
3685
                $sessionId,
3686
                $course['real_id']
3687
            );
3688
3689
            $courseIsVisible = !in_array(
3690
                $course['visibility'],
3691
                $closedVisibilityList
3692
            );
3693
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3694
                $blockedCourseCount++;
3695
            }
3696
        }
3697
3698
        // If all courses are blocked then no show in the list.
3699
        if ($blockedCourseCount === count($courseList)) {
3700
            $visibility = SESSION_INVISIBLE;
3701
        } else {
3702
            $visibility = SESSION_VISIBLE;
3703
        }
3704
    }
3705
3706
    switch ($visibility) {
3707
        case SESSION_VISIBLE_READ_ONLY:
3708
        case SESSION_VISIBLE:
3709
        case SESSION_AVAILABLE:
3710
            return true;
3711
            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...
3712
        case SESSION_INVISIBLE:
3713
            return false;
3714
    }
3715
3716
    return false;
3717
}
3718
3719
/**
3720
 * Checks if a student can edit contents in a session depending
3721
 * on the session visibility.
3722
 *
3723
 * @param bool $tutor Whether to check if the user has the tutor role
3724
 * @param bool $coach Whether to check if the user has the coach role
3725
 *
3726
 * @return bool true: the user has the rights to edit, false: he does not
3727
 */
3728
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3729
{
3730
    if (api_is_allowed_to_edit($tutor, $coach)) {
3731
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3732
        return true;
3733
    } else {
3734
        $sessionId = api_get_session_id();
3735
3736
        if (0 == $sessionId) {
3737
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3738
            return true;
3739
        } else {
3740
            // I'm in a session and I'm a student
3741
            // Get the session visibility
3742
            $session_visibility = api_get_session_visibility($sessionId);
3743
            // if 5 the session is still available
3744
            switch ($session_visibility) {
3745
                case SESSION_VISIBLE_READ_ONLY: // 1
3746
                    return false;
3747
                case SESSION_VISIBLE:           // 2
3748
                    return true;
3749
                case SESSION_INVISIBLE:         // 3
3750
                    return false;
3751
                case SESSION_AVAILABLE:         //5
3752
                    return true;
3753
            }
3754
        }
3755
    }
3756
3757
    return false;
3758
}
3759
3760
/**
3761
 * Checks whether the user is allowed in a specific tool for a specific action.
3762
 *
3763
 * @param string $tool   the tool we are checking if the user has a certain permission
3764
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3765
 *
3766
 * @return bool
3767
 *
3768
 * @author Patrick Cool <[email protected]>, Ghent University
3769
 * @author Julio Montoya
3770
 *
3771
 * @version 1.0
3772
 */
3773
function api_is_allowed($tool, $action, $task_id = 0)
3774
{
3775
    $_user = api_get_user_info();
3776
    $_course = api_get_course_info();
3777
3778
    if (api_is_course_admin()) {
3779
        return true;
3780
    }
3781
3782
    if (is_array($_course) and count($_course) > 0) {
3783
        require_once __DIR__.'/../../permissions/permissions_functions.inc.php';
3784
3785
        // Getting the permissions of this user.
3786
        if ($task_id == 0) {
3787
            $user_permissions = get_permissions('user', $_user['user_id']);
3788
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3789
        }
3790
3791
        // Getting the permissions of the task.
3792
        if ($task_id != 0) {
3793
            $task_permissions = get_permissions('task', $task_id);
3794
            $_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3795
        }
3796
        //print_r($_SESSION['total_permissions']);
3797
3798
        // Getting the permissions of the groups of the user
3799
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3800
3801
        //foreach($groups_of_user as $group)
3802
        //   $this_group_permissions = get_permissions('group', $group);
3803
3804
        // Getting the permissions of the courseroles of the user
3805
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3806
3807
        // Getting the permissions of the platformroles of the user
3808
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3809
3810
        // Getting the permissions of the roles of the groups of the user
3811
        //foreach($groups_of_user as $group)
3812
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3813
3814
        // Getting the permissions of the platformroles of the groups of the user
3815
        //foreach($groups_of_user as $group)
3816
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3817
    }
3818
3819
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3820
    if (api_get_setting('permissions') == 'limited') {
3821
        if ($action == 'Visibility') {
3822
            $action = 'Edit';
3823
        }
3824
        if ($action == 'Move') {
3825
            $action = 'Edit';
3826
        }
3827
    }
3828
3829
    // The session that contains all the permissions already exists for this course
3830
    // so there is no need to requery everything.
3831
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3832
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3833
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3834
            return true;
3835
        } else {
3836
            return false;
3837
        }
3838
    }
3839
3840
    return false;
3841
}
3842
3843
/**
3844
 * Tells whether this user is an anonymous user.
3845
 *
3846
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3847
 * @param bool $db_check Whether to check in the database (true) or simply in
3848
 *                       the session (false) to see if the current user is the anonymous user
3849
 *
3850
 * @return bool true if this user is anonymous, false otherwise
3851
 */
3852
function api_is_anonymous($user_id = null, $db_check = false)
3853
{
3854
    if (!isset($user_id)) {
3855
        $user_id = api_get_user_id();
3856
    }
3857
3858
    if ($db_check) {
3859
        $info = api_get_user_info($user_id);
3860
        if (false === $info || $info['status'] == ANONYMOUS) {
3861
            return true;
3862
        }
3863
    }
3864
3865
    $_user = api_get_user_info();
3866
3867
    if (isset($_user['status']) && $_user['status'] == ANONYMOUS) {
3868
        //if ($_user['user_id'] == 0) {
3869
        // In some cases, api_set_anonymous doesn't seem to be triggered in local.inc.php. Make sure it is.
3870
        // Occurs in agenda for admin links - YW
3871
        global $use_anonymous;
3872
        if (isset($use_anonymous) && $use_anonymous) {
3873
            api_set_anonymous();
3874
        }
3875
3876
        return true;
3877
    }
3878
3879
    return (isset($_user['is_anonymous']) && $_user['is_anonymous'] === true) || $_user === false;
3880
}
3881
3882
/**
3883
 * Displays message "You are not allowed here..." and exits the entire script.
3884
 *
3885
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3886
 * @param string $message
3887
 * @param int    $responseCode
3888
 */
3889
function api_not_allowed(
3890
    $print_headers = false,
3891
    $message = null,
3892
    $responseCode = 0
3893
) {
3894
    if (api_get_setting('sso_authentication') === 'true') {
3895
        global $osso;
3896
        if ($osso) {
3897
            $osso->logout();
3898
        }
3899
    }
3900
    $home_url = api_get_path(WEB_PATH);
3901
    $user_id = api_get_user_id();
3902
    $course = api_get_course_id();
3903
3904
    global $this_section;
3905
3906
    if (CustomPages::enabled() && !isset($user_id)) {
3907
        if (empty($user_id)) {
3908
            // Why the CustomPages::enabled() need to be to set the request_uri
3909
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3910
        }
3911
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3912
    }
3913
3914
    $origin = api_get_origin();
3915
3916
    $msg = null;
3917
    if (isset($message)) {
3918
        $msg = $message;
3919
    } else {
3920
        $msg = Display::return_message(
3921
            get_lang('NotAllowedClickBack').'
3922
            <script>function goBack(){window.history.back();}</script>',
3923
            'error',
3924
            false
3925
        );
3926
        $msg .= '<p class="text-center">
3927
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3928
             </p>';
3929
    }
3930
3931
    $msg = Display::div($msg, ['align' => 'center']);
3932
3933
    $show_headers = 0;
3934
    if ($print_headers && $origin != 'learnpath') {
3935
        $show_headers = 1;
3936
    }
3937
3938
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3939
    $tpl->assign('hide_login_link', 1);
3940
    $tpl->assign('content', $msg);
3941
3942
    if (($user_id != 0 && !api_is_anonymous()) &&
3943
        (!isset($course) || $course == -1) &&
3944
        empty($_GET['cidReq'])
3945
    ) {
3946
        // if the access is not authorized and there is some login information
3947
        // but the cidReq is not found, assume we are missing course data and send the user
3948
        // to the user_portal
3949
        $tpl->display_one_col_template();
3950
        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...
3951
    }
3952
3953
    if (!empty($_SERVER['REQUEST_URI']) &&
3954
        (
3955
            !empty($_GET['cidReq']) ||
3956
            $this_section == SECTION_MYPROFILE ||
3957
            $this_section == SECTION_PLATFORM_ADMIN
3958
        )
3959
    ) {
3960
        $courseCode = api_get_course_id();
3961
        // Only display form and return to the previous URL if there was a course ID included
3962
        if ($user_id != 0 && !api_is_anonymous()) {
3963
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3964
            $tpl->assign('content', $msg);
3965
            $tpl->display_one_col_template();
3966
            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...
3967
        }
3968
3969
        if (!is_null($courseCode)) {
3970
            api_set_firstpage_parameter($courseCode);
3971
        }
3972
3973
        // If the user has no user ID, then his session has expired
3974
        $form = api_get_not_allowed_login_form();
3975
3976
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3977
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3978
3979
        if (!empty($courseCode)) {
3980
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3981
        }
3982
3983
        if (api_is_cas_activated()) {
3984
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
3985
            $content .= Display::div(
3986
                Template::displayCASLoginButton(),
3987
                ['align' => 'center']
3988
            );
3989
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3990
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3991
            $content .= "<div style='display:none;'>";
3992
        }
3993
        $content .= '<div class="well">';
3994
        $content .= $form->returnForm();
3995
        $content .= '</div>';
3996
        if (api_is_cas_activated()) {
3997
            $content .= "</div>";
3998
        }
3999
4000
        if (!empty($courseCode)) {
4001
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
4002
                get_lang('ReturnToCourseHomepage').'</a></p>';
4003
        } else {
4004
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
4005
                get_lang('BackHome').'</a></p>';
4006
        }
4007
4008
        $tpl->setLoginBodyClass();
4009
        $tpl->assign('content', $content);
4010
        $tpl->display_one_col_template();
4011
        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...
4012
    }
4013
4014
    if ($user_id != 0 && !api_is_anonymous()) {
4015
        $tpl->display_one_col_template();
4016
        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...
4017
    }
4018
4019
    $msg = null;
4020
    // The session is over and we were not in a course,
4021
    // or we try to get directly to a private course without being logged
4022
    $courseId = api_get_course_int_id();
4023
    if (!empty($courseId)) {
4024
        api_set_firstpage_parameter(api_get_course_id());
4025
        $tpl->setLoginBodyClass();
4026
4027
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
4028
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
4029
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
4030
        $casEnabled = api_is_cas_activated();
4031
        if ($casEnabled) {
4032
            $msg .= Display::return_message(
4033
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
4034
                '',
4035
                false
4036
            );
4037
            $msg .= Display::div(
4038
                Template::displayCASLoginButton(),
4039
                ['align' => 'center']
4040
            );
4041
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
4042
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
4043
            $msg .= "<div style='display:none;'>";
4044
        }
4045
        $form = api_get_not_allowed_login_form();
4046
        $msg .= '<div class="well">';
4047
        $msg .= $form->returnForm();
4048
        $msg .= '</div>';
4049
        if ($casEnabled) {
4050
            $msg .= "</div>";
4051
        }
4052
    } else {
4053
        // we were not in a course, return to home page
4054
        $msg = Display::return_message(
4055
            get_lang('NotAllowed'),
4056
            'error',
4057
            false
4058
        );
4059
4060
        $msg .= '<p class="text-center">
4061
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
4062
                 </p>';
4063
4064
        if (!empty($message)) {
4065
            $msg = $message;
4066
        }
4067
4068
        if (api_is_anonymous()) {
4069
            $form = api_get_not_allowed_login_form();
4070
            $msg .= '<div class="well">';
4071
            $msg .= $form->returnForm();
4072
            $msg .= '</div>';
4073
        }
4074
    }
4075
4076
    $tpl->assign('content', $msg);
4077
    $tpl->display_one_col_template();
4078
    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...
4079
}
4080
4081
/**
4082
 * @return FormValidator
4083
 */
4084
function api_get_not_allowed_login_form()
4085
{
4086
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
4087
    $action = str_replace('&amp;', '&', $action);
4088
    Session::write('redirect_after_not_allow_page', $action);
4089
    $action .= '&redirect_after_not_allow_page=1';
4090
4091
    $form = new FormValidator(
4092
        'formLogin',
4093
        'post',
4094
        $action,
4095
        null,
4096
        ['class' => 'form-stacked']
4097
    );
4098
    $params = [
4099
        'placeholder' => get_lang('UserName'),
4100
        'class' => 'col-md-3',
4101
    ];
4102
    if (api_browser_support('autocapitalize')) {
4103
        $params['autocapitalize'] = 'none';
4104
    }
4105
4106
    $form->addElement(
4107
        'text',
4108
        'login',
4109
        null,
4110
        $params
4111
    );
4112
    $form->addElement(
4113
        'password',
4114
        'password',
4115
        null,
4116
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
4117
    ); //new
4118
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
4119
4120
    return $form;
4121
}
4122
4123
/**
4124
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
4125
 *
4126
 * @param string $last_post_datetime standard output date in a sql query
4127
 *
4128
 * @return int timestamp
4129
 *
4130
 * @author Toon Van Hoecke <[email protected]>
4131
 *
4132
 * @version October 2003
4133
 * @desc convert sql date to unix timestamp
4134
 */
4135
function convert_sql_date($last_post_datetime)
4136
{
4137
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
4138
    list($year, $month, $day) = explode('-', $last_post_date);
4139
    list($hour, $min, $sec) = explode(':', $last_post_time);
4140
4141
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
4142
}
4143
4144
/**
4145
 * Gets item visibility from the item_property table.
4146
 *
4147
 * Getting the visibility is done by getting the last updated visibility entry,
4148
 * using the largest session ID found if session 0 and another was found (meaning
4149
 * the only one that is actually from the session, in case there are results from
4150
 * session 0 *AND* session n).
4151
 *
4152
 * @param array  $_course  Course properties array (result of api_get_course_info())
4153
 * @param string $tool     Tool (learnpath, document, etc)
4154
 * @param int    $id       The item ID in the given tool
4155
 * @param int    $session  The session ID (optional)
4156
 * @param int    $user_id
4157
 * @param string $type
4158
 * @param string $group_id
4159
 *
4160
 * @return int -1 on error, 0 if invisible, 1 if visible
4161
 */
4162
function api_get_item_visibility(
4163
    $_course,
4164
    $tool,
4165
    $id,
4166
    $session = 0,
4167
    $user_id = null,
4168
    $type = null,
4169
    $group_id = null
4170
) {
4171
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4172
        return -1;
4173
    }
4174
4175
    $tool = Database::escape_string($tool);
4176
    $id = (int) $id;
4177
    $session = (int) $session;
4178
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4179
    $course_id = (int) $_course['real_id'];
4180
4181
    $userCondition = '';
4182
    if (!empty($user_id)) {
4183
        $user_id = (int) $user_id;
4184
        $userCondition = " AND to_user_id = $user_id ";
4185
    }
4186
4187
    $typeCondition = '';
4188
    if (!empty($type)) {
4189
        $type = Database::escape_string($type);
4190
        $typeCondition = " AND lastedit_type = '$type' ";
4191
    }
4192
4193
    $groupCondition = '';
4194
    if (!empty($group_id)) {
4195
        $group_id = (int) $group_id;
4196
        $groupCondition = " AND to_group_id = '$group_id' ";
4197
    }
4198
4199
    $sql = "SELECT visibility
4200
            FROM $TABLE_ITEMPROPERTY
4201
            WHERE
4202
                c_id = $course_id AND
4203
                tool = '$tool' AND
4204
                ref = $id AND
4205
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4206
                $userCondition $typeCondition $groupCondition
4207
            ORDER BY session_id DESC, lastedit_date DESC
4208
            LIMIT 1";
4209
4210
    $res = Database::query($sql);
4211
    if ($res === false || Database::num_rows($res) == 0) {
4212
        return -1;
4213
    }
4214
    $row = Database::fetch_array($res);
4215
4216
    return (int) $row['visibility'];
4217
}
4218
4219
/**
4220
 * Delete a row in the c_item_property table.
4221
 *
4222
 * @param array  $courseInfo
4223
 * @param string $tool
4224
 * @param int    $itemId
4225
 * @param int    $userId
4226
 * @param int    $groupId    group.iid
4227
 * @param int    $sessionId
4228
 *
4229
 * @return false|null
4230
 */
4231
function api_item_property_delete(
4232
    $courseInfo,
4233
    $tool,
4234
    $itemId,
4235
    $userId,
4236
    $groupId = 0,
4237
    $sessionId = 0
4238
) {
4239
    if (empty($courseInfo)) {
4240
        return false;
4241
    }
4242
4243
    $courseId = (int) $courseInfo['real_id'];
4244
4245
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4246
        return false;
4247
    }
4248
4249
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4250
    $tool = Database::escape_string($tool);
4251
    $itemId = intval($itemId);
4252
    $userId = intval($userId);
4253
    $groupId = intval($groupId);
4254
    $sessionId = intval($sessionId);
4255
4256
    $groupCondition = " AND to_group_id = $groupId ";
4257
    if (empty($groupId)) {
4258
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4259
    }
4260
4261
    $userCondition = " AND to_user_id = $userId ";
4262
    if (empty($userId)) {
4263
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4264
    }
4265
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4266
    $sql = "DELETE FROM $table
4267
            WHERE
4268
                c_id = $courseId AND
4269
                tool  = '$tool' AND
4270
                ref = $itemId
4271
                $sessionCondition
4272
                $userCondition
4273
                $groupCondition
4274
            ";
4275
4276
    Database::query($sql);
4277
}
4278
4279
/**
4280
 * Updates or adds item properties to the Item_propetry table
4281
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4282
 *
4283
 * @param array  $_course        array with course properties
4284
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4285
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4286
 * @param string $last_edit_type add or update action
4287
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4288
 *                               (2) "delete"
4289
 *                               (3) "visible"
4290
 *                               (4) "invisible"
4291
 * @param int    $user_id        id of the editing/adding user
4292
 * @param array  $groupInfo      must include group.iid/group.od
4293
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4294
 * @param string $start_visible  0000-00-00 00:00:00 format
4295
 * @param string $end_visible    0000-00-00 00:00:00 format
4296
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4297
 *
4298
 * @return bool false if update fails
4299
 *
4300
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4301
 *
4302
 * @version January 2005
4303
 * @desc update the item_properties table (if entry not exists, insert) of the course
4304
 */
4305
function api_item_property_update(
4306
    $_course,
4307
    $tool,
4308
    $item_id,
4309
    $last_edit_type,
4310
    $user_id,
4311
    $groupInfo = [],
4312
    $to_user_id = null,
4313
    $start_visible = '',
4314
    $end_visible = '',
4315
    $session_id = 0
4316
) {
4317
    if (empty($_course)) {
4318
        return false;
4319
    }
4320
4321
    $course_id = $_course['real_id'];
4322
4323
    if (empty($course_id)) {
4324
        return false;
4325
    }
4326
4327
    $to_group_id = 0;
4328
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4329
        $to_group_id = (int) $groupInfo['iid'];
4330
    }
4331
4332
    $em = Database::getManager();
4333
4334
    // Definition of variables.
4335
    $tool = Database::escape_string($tool);
4336
    $item_id = (int) $item_id;
4337
    $lastEditTypeNoFilter = $last_edit_type;
4338
    $last_edit_type = Database::escape_string($last_edit_type);
4339
    $user_id = (int) $user_id;
4340
4341
    $startVisible = "NULL";
4342
    if (!empty($start_visible)) {
4343
        $start_visible = Database::escape_string($start_visible);
4344
        $startVisible = "'$start_visible'";
4345
    }
4346
4347
    $endVisible = "NULL";
4348
    if (!empty($end_visible)) {
4349
        $end_visible = Database::escape_string($end_visible);
4350
        $endVisible = "'$end_visible'";
4351
    }
4352
4353
    $to_filter = '';
4354
    $time = api_get_utc_datetime();
4355
4356
    if (!empty($session_id)) {
4357
        $session_id = (int) $session_id;
4358
    } else {
4359
        $session_id = api_get_session_id();
4360
    }
4361
4362
    // Definition of tables.
4363
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4364
4365
    if ($to_user_id <= 0) {
4366
        $to_user_id = null; // No to_user_id set
4367
    }
4368
4369
    if (!is_null($to_user_id)) {
4370
        // $to_user_id has more priority than $to_group_id
4371
        $to_user_id = (int) $to_user_id;
4372
        $to_field = 'to_user_id';
4373
        $to_value = $to_user_id;
4374
    } else {
4375
        // $to_user_id is not set.
4376
        $to_field = 'to_group_id';
4377
        $to_value = $to_group_id;
4378
    }
4379
4380
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4381
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4382
    $condition_session = " AND session_id = $session_id ";
4383
    if (empty($session_id)) {
4384
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4385
    }
4386
4387
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4388
4389
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4390
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4391
    if (is_null($to_user_id) && is_null($to_group_id)) {
4392
        $to_group_id = 0;
4393
    }
4394
4395
    if (!is_null($to_user_id)) {
4396
        // Set filter to intended user.
4397
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4398
    } else {
4399
        // Set filter to intended group.
4400
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4401
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4402
        }
4403
    }
4404
4405
    // Adding filter if set.
4406
    $filter .= $to_filter;
4407
4408
    // Update if possible
4409
    $set_type = '';
4410
4411
    switch ($lastEditTypeNoFilter) {
4412
        case 'delete':
4413
            // delete = make item only visible for the platform admin.
4414
            $visibility = '2';
4415
            if (!empty($session_id)) {
4416
                // Check whether session id already exist into item_properties for updating visibility or add it.
4417
                $sql = "SELECT session_id FROM $tableItemProperty
4418
                        WHERE
4419
                            c_id = $course_id AND
4420
                            tool = '$tool' AND
4421
                            ref = $item_id AND
4422
                            session_id = $session_id";
4423
                $rs = Database::query($sql);
4424
                if (Database::num_rows($rs) > 0) {
4425
                    $sql = "UPDATE $tableItemProperty
4426
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4427
                                lastedit_date       = '$time',
4428
                                lastedit_user_id    = $user_id,
4429
                                visibility          = $visibility,
4430
                                session_id          = $session_id $set_type
4431
                            WHERE $filter";
4432
                    $result = Database::query($sql);
4433
                } else {
4434
                    $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)
4435
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4436
                    $result = Database::query($sql);
4437
                    $id = Database::insert_id();
4438
                    if ($id) {
4439
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4440
                        Database::query($sql);
4441
                    }
4442
                }
4443
            } else {
4444
                $sql = "UPDATE $tableItemProperty
4445
                        SET
4446
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4447
                            lastedit_date='$time',
4448
                            lastedit_user_id = $user_id,
4449
                            visibility = $visibility $set_type
4450
                        WHERE $filter";
4451
                $result = Database::query($sql);
4452
            }
4453
            break;
4454
        case 'visible': // Change item to visible.
4455
            $visibility = '1';
4456
            if (!empty($session_id)) {
4457
                // Check whether session id already exist into item_properties for updating visibility or add it.
4458
                $sql = "SELECT session_id FROM $tableItemProperty
4459
                        WHERE
4460
                            c_id = $course_id AND
4461
                            tool = '$tool' AND
4462
                            ref = $item_id AND
4463
                            session_id = $session_id";
4464
                $rs = Database::query($sql);
4465
                if (Database::num_rows($rs) > 0) {
4466
                    $sql = "UPDATE $tableItemProperty
4467
                            SET
4468
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4469
                                lastedit_date='$time',
4470
                                lastedit_user_id = $user_id,
4471
                                visibility = $visibility,
4472
                                session_id = $session_id $set_type
4473
                            WHERE $filter";
4474
                    $result = Database::query($sql);
4475
                } else {
4476
                    $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)
4477
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4478
                    $result = Database::query($sql);
4479
                    $id = Database::insert_id();
4480
                    if ($id) {
4481
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4482
                        Database::query($sql);
4483
                    }
4484
                }
4485
            } else {
4486
                $sql = "UPDATE $tableItemProperty
4487
                        SET
4488
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4489
                            lastedit_date='$time',
4490
                            lastedit_user_id = $user_id,
4491
                            visibility = $visibility $set_type
4492
                        WHERE $filter";
4493
                $result = Database::query($sql);
4494
            }
4495
            break;
4496
        case 'invisible': // Change item to invisible.
4497
            $visibility = '0';
4498
            if (!empty($session_id)) {
4499
                // Check whether session id already exist into item_properties for updating visibility or add it
4500
                $sql = "SELECT session_id FROM $tableItemProperty
4501
                        WHERE
4502
                            c_id = $course_id AND
4503
                            tool = '$tool' AND
4504
                            ref = $item_id AND
4505
                            session_id = $session_id";
4506
                $rs = Database::query($sql);
4507
                if (Database::num_rows($rs) > 0) {
4508
                    $sql = "UPDATE $tableItemProperty
4509
                            SET
4510
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4511
                                lastedit_date = '$time',
4512
                                lastedit_user_id = $user_id,
4513
                                visibility = $visibility,
4514
                                session_id = $session_id $set_type
4515
                            WHERE $filter";
4516
                    $result = Database::query($sql);
4517
                } else {
4518
                    $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)
4519
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4520
                    $result = Database::query($sql);
4521
                    $id = Database::insert_id();
4522
                    if ($id) {
4523
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4524
                        Database::query($sql);
4525
                    }
4526
                }
4527
            } else {
4528
                $sql = "UPDATE $tableItemProperty
4529
                        SET
4530
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4531
                            lastedit_date = '$time',
4532
                            lastedit_user_id = $user_id,
4533
                            visibility = $visibility $set_type
4534
                        WHERE $filter";
4535
                $result = Database::query($sql);
4536
            }
4537
            break;
4538
        default: // The item will be added or updated.
4539
            $set_type = ", lastedit_type = '$last_edit_type' ";
4540
            $visibility = '1';
4541
            //$filter .= $to_filter; already added
4542
            $sql = "UPDATE $tableItemProperty
4543
                    SET
4544
                      lastedit_date = '$time',
4545
                      lastedit_user_id = $user_id $set_type
4546
                    WHERE $filter";
4547
            $result = Database::query($sql);
4548
    }
4549
4550
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4551
    if ($result == false || Database::affected_rows($result) == 0) {
4552
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4553
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4554
        $objUser = api_get_user_entity($user_id);
4555
        if (empty($objUser)) {
4556
            // Use anonymous
4557
            $user_id = api_get_anonymous_id();
4558
            $objUser = api_get_user_entity($user_id);
4559
        }
4560
4561
        $objGroup = null;
4562
        if (!empty($to_group_id)) {
4563
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4564
        }
4565
4566
        $objToUser = api_get_user_entity($to_user_id);
4567
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4568
4569
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4570
        $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...
4571
4572
        $cItemProperty = new CItemProperty($objCourse);
4573
        $cItemProperty
4574
            ->setTool($tool)
4575
            ->setRef($item_id)
4576
            ->setInsertDate($objTime)
4577
            ->setInsertUser($objUser)
4578
            ->setLasteditDate($objTime)
4579
            ->setLasteditType($last_edit_type)
4580
            ->setGroup($objGroup)
4581
            ->setToUser($objToUser)
4582
            ->setVisibility($visibility)
4583
            ->setStartVisible($startVisibleDate)
4584
            ->setEndVisible($endVisibleDate)
4585
            ->setSession($objSession);
4586
4587
        $em->persist($cItemProperty);
4588
        $em->flush();
4589
4590
        $id = $cItemProperty->getIid();
4591
4592
        if ($id) {
4593
            $cItemProperty->setId($id);
4594
            $em->merge($cItemProperty);
4595
            $em->flush();
4596
4597
            return false;
4598
        }
4599
    }
4600
4601
    return true;
4602
}
4603
4604
/**
4605
 * Gets item property by tool.
4606
 *
4607
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4608
 * @param string $course_code
4609
 * @param int    $session_id
4610
 *
4611
 * @return array All fields from c_item_property (all rows found) or empty array
4612
 */
4613
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4614
{
4615
    $course_info = api_get_course_info($course_code);
4616
    $tool = Database::escape_string($tool);
4617
4618
    // Definition of tables.
4619
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4620
    $session_id = (int) $session_id;
4621
    $session_condition = ' AND session_id = '.$session_id;
4622
    if (empty($session_id)) {
4623
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4624
    }
4625
    $course_id = $course_info['real_id'];
4626
4627
    $sql = "SELECT * FROM $item_property_table
4628
            WHERE
4629
                c_id = $course_id AND
4630
                tool = '$tool'
4631
                $session_condition ";
4632
    $rs = Database::query($sql);
4633
    $list = [];
4634
    if (Database::num_rows($rs) > 0) {
4635
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4636
            $list[] = $row;
4637
        }
4638
    }
4639
4640
    return $list;
4641
}
4642
4643
/**
4644
 * Gets item property by tool and user.
4645
 *
4646
 * @param int $userId
4647
 * @param int $tool
4648
 * @param int $courseId
4649
 * @param int $session_id
4650
 *
4651
 * @return array
4652
 */
4653
function api_get_item_property_list_by_tool_by_user(
4654
    $userId,
4655
    $tool,
4656
    $courseId,
4657
    $session_id = 0
4658
) {
4659
    $userId = intval($userId);
4660
    $tool = Database::escape_string($tool);
4661
    $session_id = intval($session_id);
4662
    $courseId = intval($courseId);
4663
4664
    // Definition of tables.
4665
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4666
    $session_condition = ' AND session_id = '.$session_id;
4667
    if (empty($session_id)) {
4668
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4669
    }
4670
    $sql = "SELECT * FROM $item_property_table
4671
            WHERE
4672
                insert_user_id = $userId AND
4673
                c_id = $courseId AND
4674
                tool = '$tool'
4675
                $session_condition ";
4676
4677
    $rs = Database::query($sql);
4678
    $list = [];
4679
    if (Database::num_rows($rs) > 0) {
4680
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4681
            $list[] = $row;
4682
        }
4683
    }
4684
4685
    return $list;
4686
}
4687
4688
/**
4689
 * Gets item property id from tool of a course.
4690
 *
4691
 * @param string $course_code course code
4692
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4693
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4694
 * @param int    $sessionId   Session ID (optional)
4695
 *
4696
 * @return int
4697
 */
4698
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4699
{
4700
    $course_info = api_get_course_info($course_code);
4701
    $tool = Database::escape_string($tool);
4702
    $ref = (int) $ref;
4703
4704
    // Definition of tables.
4705
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4706
    $course_id = $course_info['real_id'];
4707
    $sessionId = (int) $sessionId;
4708
    $sessionCondition = " AND session_id = $sessionId ";
4709
    if (empty($sessionId)) {
4710
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4711
    }
4712
    $sql = "SELECT id FROM $tableItemProperty
4713
            WHERE
4714
                c_id = $course_id AND
4715
                tool = '$tool' AND
4716
                ref = $ref
4717
                $sessionCondition";
4718
    $rs = Database::query($sql);
4719
    $item_property_id = '';
4720
    if (Database::num_rows($rs) > 0) {
4721
        $row = Database::fetch_array($rs);
4722
        $item_property_id = $row['id'];
4723
    }
4724
4725
    return $item_property_id;
4726
}
4727
4728
/**
4729
 * Inserts a record in the track_e_item_property table (No update).
4730
 *
4731
 * @param string $tool
4732
 * @param int    $ref
4733
 * @param string $title
4734
 * @param string $content
4735
 * @param int    $progress
4736
 *
4737
 * @return bool|int
4738
 */
4739
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4740
{
4741
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4742
    $course_id = api_get_course_int_id(); //numeric
4743
    $course_code = api_get_course_id(); //alphanumeric
4744
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4745
    if (!empty($item_property_id)) {
4746
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4747
                course_id           = '$course_id',
4748
                item_property_id    = '$item_property_id',
4749
                title               = '".Database::escape_string($title)."',
4750
                content             = '".Database::escape_string($content)."',
4751
                progress            = '".intval($progress)."',
4752
                lastedit_date       = '".api_get_utc_datetime()."',
4753
                lastedit_user_id    = '".api_get_user_id()."',
4754
                session_id          = '".api_get_session_id()."'";
4755
        $result = Database::query($sql);
4756
        $affected_rows = Database::affected_rows($result);
4757
4758
        return $affected_rows;
4759
    }
4760
4761
    return false;
4762
}
4763
4764
/**
4765
 * @param string $tool
4766
 * @param int    $ref
4767
 *
4768
 * @return array|resource
4769
 */
4770
function api_get_track_item_property_history($tool, $ref)
4771
{
4772
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4773
    $course_id = api_get_course_int_id(); //numeric
4774
    $course_code = api_get_course_id(); //alphanumeric
4775
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4776
    $sql = "SELECT * FROM $tbl_stats_item_property
4777
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4778
            ORDER BY lastedit_date DESC";
4779
    $result = Database::query($sql);
4780
    if ($result === false or $result === null) {
4781
        $result = [];
4782
    } else {
4783
        $result = Database::store_result($result, 'ASSOC');
4784
    }
4785
4786
    return $result;
4787
}
4788
4789
/**
4790
 * Gets item property data from tool of a course id.
4791
 *
4792
 * @param int    $course_id
4793
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4794
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4795
 * @param int    $session_id
4796
 * @param int    $groupId
4797
 *
4798
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4799
 */
4800
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4801
{
4802
    $courseInfo = api_get_course_info_by_id($course_id);
4803
4804
    if (empty($courseInfo)) {
4805
        return false;
4806
    }
4807
4808
    $tool = Database::escape_string($tool);
4809
    $course_id = $courseInfo['real_id'];
4810
    $ref = (int) $ref;
4811
    $session_id = (int) $session_id;
4812
4813
    $sessionCondition = " session_id = $session_id";
4814
    if (empty($session_id)) {
4815
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4816
    }
4817
4818
    // Definition of tables.
4819
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4820
4821
    $sql = "SELECT * FROM $table
4822
            WHERE
4823
                c_id = $course_id AND
4824
                tool = '$tool' AND
4825
                ref = $ref AND
4826
                $sessionCondition ";
4827
4828
    if (!empty($groupId)) {
4829
        $groupId = (int) $groupId;
4830
        $sql .= " AND to_group_id = $groupId ";
4831
    }
4832
4833
    $rs = Database::query($sql);
4834
    $row = [];
4835
    if (Database::num_rows($rs) > 0) {
4836
        $row = Database::fetch_array($rs, 'ASSOC');
4837
    }
4838
4839
    return $row;
4840
}
4841
4842
/**
4843
 * Displays a combo box so the user can select his/her preferred language.
4844
 *
4845
 * @param string The desired name= value for the select
4846
 * @param bool Whether we use the JQuery Chozen library or not
4847
 * (in some cases, like the indexing language picker, it can alter the presentation)
4848
 *
4849
 * @return string
4850
 */
4851
function api_get_languages_combo($name = 'language')
4852
{
4853
    $ret = '';
4854
    $platformLanguage = api_get_setting('platformLanguage');
4855
4856
    // Retrieve a complete list of all the languages.
4857
    $language_list = api_get_languages();
4858
4859
    if (count($language_list['name']) < 2) {
4860
        return $ret;
4861
    }
4862
4863
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4864
    if (isset($_SESSION['user_language_choice'])) {
4865
        $default = $_SESSION['user_language_choice'];
4866
    } else {
4867
        $default = $platformLanguage;
4868
    }
4869
4870
    $languages = $language_list['name'];
4871
    $folder = $language_list['folder'];
4872
4873
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker form-control">';
4874
    foreach ($languages as $key => $value) {
4875
        if ($folder[$key] == $default) {
4876
            $selected = ' selected="selected"';
4877
        } else {
4878
            $selected = '';
4879
        }
4880
        $ret .= sprintf('<option value=%s" %s>%s</option>', $folder[$key], $selected, $value);
4881
    }
4882
    $ret .= '</select>';
4883
4884
    return $ret;
4885
}
4886
4887
/**
4888
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4889
 * The form works with or without javascript.
4890
 *
4891
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4892
 * @param bool $showAsButton
4893
 *
4894
 * @return string|null Display the box directly
4895
 */
4896
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4897
{
4898
    // Retrieve a complete list of all the languages.
4899
    $language_list = api_get_languages();
4900
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4901
        return null; //don't show any form
4902
    }
4903
4904
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4905
    if (isset($_SESSION['user_language_choice'])) {
4906
        $user_selected_language = $_SESSION['user_language_choice'];
4907
    }
4908
    if (empty($user_selected_language)) {
4909
        $user_selected_language = api_get_setting('platformLanguage');
4910
    }
4911
4912
    $currentLanguageId = api_get_language_id($user_selected_language);
4913
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4914
4915
    $countryCode = languageCodeToCountryIsoCodeForFlags($currentLanguageInfo['isocode']);
4916
    $url = api_get_self();
4917
    if ($showAsButton) {
4918
        $html = '<div class="btn-group">
4919
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4920
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4921
                '.$currentLanguageInfo['original_name'].'
4922
                <span class="caret">
4923
                </span>
4924
              </button>';
4925
    } else {
4926
        $html = '
4927
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4928
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4929
                '.$currentLanguageInfo['original_name'].'
4930
                <span class="caret"></span>
4931
            </a>
4932
            ';
4933
    }
4934
4935
    $html .= '<ul class="dropdown-menu" role="menu">';
4936
    foreach ($language_list['all'] as $key => $data) {
4937
        $urlLink = $url.'?language='.$data['english_name'];
4938
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageCodeToCountryIsoCodeForFlags($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4939
    }
4940
    $html .= '</ul>';
4941
4942
    if ($showAsButton) {
4943
        $html .= '</div>';
4944
    }
4945
4946
    return $html;
4947
}
4948
4949
/**
4950
 * Return a country code based on a language in order to show a country flag.
4951
 * Note: Showing a "language" flag is arguably a bad idea, as several countries
4952
 * share languages and the right flag cannot be shown for all of them.
4953
 *
4954
 * @param string $languageIsoCode
4955
 *
4956
 * @return string
4957
 */
4958
function languageCodeToCountryIsoCodeForFlags($languageIsoCode)
4959
{
4960
    $allow = api_get_configuration_value('language_flags_by_country');
4961
4962
    // @todo save in DB
4963
    switch ($languageIsoCode) {
4964
        case 'ar':
4965
            $country = 'ae';
4966
            break;
4967
        case 'bs':
4968
            $country = 'ba';
4969
            break;
4970
        case 'ca':
4971
            $country = 'es';
4972
            if ($allow) {
4973
                $country = 'catalan';
4974
            }
4975
            break;
4976
        case 'cs':
4977
            $country = 'cz';
4978
            break;
4979
        case 'da':
4980
            $country = 'dk';
4981
            break;
4982
        case 'el':
4983
            $country = 'gr';
4984
            break;
4985
        case 'en':
4986
            $country = 'gb';
4987
            break;
4988
        case 'eu': // Euskera
4989
            $country = 'es';
4990
            if ($allow) {
4991
                $country = 'basque';
4992
            }
4993
            break;
4994
        case 'gl': // galego
4995
            $country = 'es';
4996
            if ($allow) {
4997
                $country = 'galician';
4998
            }
4999
            break;
5000
        case 'he':
5001
            $country = 'il';
5002
            break;
5003
        case 'ja':
5004
            $country = 'jp';
5005
            break;
5006
        case 'ka':
5007
            $country = 'ge';
5008
            break;
5009
        case 'ko':
5010
            $country = 'kr';
5011
            break;
5012
        case 'ms':
5013
            $country = 'my';
5014
            break;
5015
        case 'pt-BR':
5016
            $country = 'br';
5017
            break;
5018
        case 'qu':
5019
            $country = 'pe';
5020
            break;
5021
        case 'sl':
5022
            $country = 'si';
5023
            break;
5024
        case 'sv':
5025
            $country = 'se';
5026
            break;
5027
        case 'uk': // Ukraine
5028
            $country = 'ua';
5029
            break;
5030
        case 'zh-TW':
5031
        case 'zh':
5032
            $country = 'cn';
5033
            break;
5034
        default:
5035
            $country = $languageIsoCode;
5036
            break;
5037
    }
5038
    $country = strtolower($country);
5039
5040
    return $country;
5041
}
5042
5043
/**
5044
 * Returns a list of all the languages that are made available by the admin.
5045
 *
5046
 * @return array An array with all languages. Structure of the array is
5047
 *               array['name'] = An array with the name of every language
5048
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
5049
 */
5050
function api_get_languages()
5051
{
5052
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5053
    $sql = "SELECT * FROM $tbl_language WHERE available='1'
5054
            ORDER BY original_name ASC";
5055
    $result = Database::query($sql);
5056
    $language_list = [];
5057
    while ($row = Database::fetch_array($result)) {
5058
        $language_list['name'][] = $row['original_name'];
5059
        $language_list['folder'][] = $row['dokeos_folder'];
5060
        $language_list['all'][] = $row;
5061
    }
5062
5063
    return $language_list;
5064
}
5065
5066
/**
5067
 * Returns a list of all the languages that are made available by the admin.
5068
 *
5069
 * @return array
5070
 */
5071
function api_get_languages_to_array()
5072
{
5073
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5074
    $sql = "SELECT * FROM $tbl_language
5075
            WHERE available='1' ORDER BY original_name ASC";
5076
    $result = Database::query($sql);
5077
    $languages = [];
5078
    while ($row = Database::fetch_array($result)) {
5079
        $languages[$row['dokeos_folder']] = $row['original_name'];
5080
    }
5081
5082
    return $languages;
5083
}
5084
5085
/**
5086
 * Returns the id (the database id) of a language.
5087
 *
5088
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
5089
 *
5090
 * @return int id of the language
5091
 */
5092
function api_get_language_id($language)
5093
{
5094
    if (empty($language)) {
5095
        return null;
5096
    }
5097
5098
    static $staticResult;
5099
5100
    if (isset($staticResult[$language])) {
5101
        return $staticResult[$language];
5102
    } else {
5103
        $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5104
        $language = Database::escape_string($language);
5105
        $sql = "SELECT id FROM $table
5106
                WHERE dokeos_folder = '$language' LIMIT 1";
5107
        $result = Database::query($sql);
5108
        $row = Database::fetch_array($result);
5109
5110
        $staticResult[$language] = $row['id'];
5111
5112
        return $row['id'];
5113
    }
5114
}
5115
5116
/**
5117
 * Gets language of the requested type for the current user. Types are :
5118
 * user_profil_lang : profile language of current user
5119
 * user_select_lang : language selected by user at login
5120
 * course_lang : language of the current course
5121
 * platform_lang : default platform language.
5122
 *
5123
 * @param string $lang_type
5124
 *
5125
 * @return string
5126
 */
5127
function api_get_language_from_type($lang_type)
5128
{
5129
    $return = false;
5130
    switch ($lang_type) {
5131
        case 'platform_lang':
5132
            $temp_lang = api_get_setting('platformLanguage');
5133
            if (!empty($temp_lang)) {
5134
                $return = $temp_lang;
5135
            }
5136
            break;
5137
        case 'user_profil_lang':
5138
            $_user = api_get_user_info();
5139
            if (isset($_user['language']) && !empty($_user['language'])) {
5140
                $return = $_user['language'];
5141
            }
5142
            break;
5143
        case 'user_selected_lang':
5144
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
5145
                $return = $_SESSION['user_language_choice'];
5146
            }
5147
            break;
5148
        case 'course_lang':
5149
            global $_course;
5150
            $cidReq = null;
5151
            if (empty($_course)) {
5152
                // Code modified because the local.inc.php file it's declarated after this work
5153
                // causing the function api_get_course_info() returns a null value
5154
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
5155
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
5156
                if (empty($cidReq) && !empty($cDir)) {
5157
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
5158
                    if ($c) {
5159
                        $cidReq = $c;
5160
                    }
5161
                }
5162
            }
5163
            $_course = api_get_course_info($cidReq);
5164
            if (isset($_course['language']) && !empty($_course['language'])) {
5165
                $return = $_course['language'];
5166
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
5167
                if ($showCourseInUserLanguage == 1) {
5168
                    $userInfo = api_get_user_info();
5169
                    if (isset($userInfo['language'])) {
5170
                        $return = $userInfo['language'];
5171
                    }
5172
                }
5173
            }
5174
            break;
5175
        default:
5176
            $return = false;
5177
            break;
5178
    }
5179
5180
    return $return;
5181
}
5182
5183
/**
5184
 * Get the language information by its id.
5185
 *
5186
 * @param int $languageId
5187
 *
5188
 * @throws Exception
5189
 *
5190
 * @return array
5191
 */
5192
function api_get_language_info($languageId)
5193
{
5194
    if (empty($languageId)) {
5195
        return [];
5196
    }
5197
5198
    $language = Database::getManager()
5199
        ->find('ChamiloCoreBundle:Language', $languageId);
5200
5201
    if (!$language) {
5202
        return [];
5203
    }
5204
5205
    return [
5206
        'id' => $language->getId(),
5207
        'original_name' => $language->getOriginalName(),
5208
        'english_name' => $language->getEnglishName(),
5209
        'isocode' => $language->getIsocode(),
5210
        'dokeos_folder' => $language->getDokeosFolder(),
5211
        'available' => $language->getAvailable(),
5212
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
5213
    ];
5214
}
5215
5216
/**
5217
 * Returns the name of the visual (CSS) theme to be applied on the current page.
5218
 * The returned name depends on the platform, course or user -wide settings.
5219
 *
5220
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
5221
 */
5222
function api_get_visual_theme()
5223
{
5224
    static $visual_theme;
5225
5226
    // If call from CLI it should be reload.
5227
    if ('cli' === PHP_SAPI) {
5228
        $visual_theme = null;
5229
    }
5230
5231
    if (!isset($visual_theme)) {
5232
        $cacheAvailable = api_get_configuration_value('apc');
5233
        $userThemeAvailable = api_get_setting('user_selected_theme') == 'true';
5234
        $courseThemeAvailable = api_get_setting('allow_course_theme') == 'true';
5235
        // only use a shared cache if no user-based or course-based theme is allowed
5236
        $useCache = ($cacheAvailable && !$userThemeAvailable && !$courseThemeAvailable);
5237
        $apcVar = '';
5238
        if ($useCache) {
5239
            $apcVar = api_get_configuration_value('apc_prefix').'my_campus_visual_theme';
5240
            if (apcu_exists($apcVar)) {
5241
                return apcu_fetch($apcVar);
5242
            }
5243
        }
5244
5245
        $accessUrlId = api_get_current_access_url_id();
5246
        if ('cli' === PHP_SAPI) {
5247
            $accessUrlId = api_get_configuration_value('access_url');
5248
        }
5249
5250
        // Get style directly from DB
5251
        $styleFromDatabase = api_get_settings_params_simple(
5252
            [
5253
                'variable = ? AND access_url = ?' => [
5254
                    'stylesheets',
5255
                    $accessUrlId,
5256
                ],
5257
            ]
5258
        );
5259
        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...
5260
            $platform_theme = $styleFromDatabase['selected_value'];
5261
        } else {
5262
            $platform_theme = api_get_setting('stylesheets');
5263
        }
5264
5265
        // Platform's theme.
5266
        $visual_theme = $platform_theme;
5267
        if ($userThemeAvailable) {
5268
            $user_info = api_get_user_info();
5269
            if (isset($user_info['theme'])) {
5270
                $user_theme = $user_info['theme'];
5271
5272
                if (!empty($user_theme)) {
5273
                    $visual_theme = $user_theme;
5274
                    // User's theme.
5275
                }
5276
            }
5277
        }
5278
5279
        $course_id = api_get_course_id();
5280
        if (!empty($course_id)) {
5281
            if ($courseThemeAvailable) {
5282
                $course_theme = api_get_course_setting('course_theme', api_get_course_info());
5283
5284
                if (!empty($course_theme) && $course_theme != -1) {
5285
                    if (!empty($course_theme)) {
5286
                        // Course's theme.
5287
                        $visual_theme = $course_theme;
5288
                    }
5289
                }
5290
5291
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5292
                if ($allow_lp_theme == 1) {
5293
                    global $lp_theme_css, $lp_theme_config;
5294
                    // These variables come from the file lp_controller.php.
5295
                    if (!$lp_theme_config) {
5296
                        if (!empty($lp_theme_css)) {
5297
                            // LP's theme.
5298
                            $visual_theme = $lp_theme_css;
5299
                        }
5300
                    }
5301
                }
5302
            }
5303
        }
5304
5305
        if (empty($visual_theme)) {
5306
            $visual_theme = 'chamilo';
5307
        }
5308
5309
        global $lp_theme_log;
5310
        if ($lp_theme_log) {
5311
            $visual_theme = $platform_theme;
5312
        }
5313
        if ($useCache) {
5314
            apcu_store($apcVar, $visual_theme, 120);
5315
        }
5316
    }
5317
5318
    return $visual_theme;
5319
}
5320
5321
/**
5322
 * Returns a list of CSS themes currently available in the CSS folder
5323
 * The folder must have a default.css file.
5324
 *
5325
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5326
 *
5327
 * @return array list of themes directories from the css folder
5328
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5329
 */
5330
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5331
{
5332
    // This configuration value is set by the vchamilo plugin
5333
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5334
5335
    $readCssFolder = function ($dir) use ($virtualTheme) {
5336
        $finder = new Finder();
5337
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5338
        $list = [];
5339
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5340
        foreach ($themes as $theme) {
5341
            $folder = $theme->getFilename();
5342
            // A theme folder is consider if there's a default.css file
5343
            if (!file_exists($theme->getPathname().'/default.css')) {
5344
                continue;
5345
            }
5346
            $name = ucwords(str_replace('_', ' ', $folder));
5347
            if ($folder == $virtualTheme) {
5348
                continue;
5349
            }
5350
            $list[$folder] = $name;
5351
        }
5352
5353
        return $list;
5354
    };
5355
5356
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5357
    $list = $readCssFolder($dir);
5358
5359
    if (!empty($virtualTheme)) {
5360
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5361
        if ($getOnlyThemeFromVirtualInstance) {
5362
            return $newList;
5363
        }
5364
        $list = $list + $newList;
5365
        asort($list);
5366
    }
5367
5368
    return $list;
5369
}
5370
5371
/**
5372
 * Find the largest sort value in a given user_course_category
5373
 * This function is used when we are moving a course to a different category
5374
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5375
 *
5376
 * @author Patrick Cool <[email protected]>, Ghent University
5377
 *
5378
 * @param int $user_course_category the id of the user_course_category
5379
 * @param int $user_id
5380
 *
5381
 * @return int the value of the highest sort of the user_course_category
5382
 */
5383
function api_max_sort_value($user_course_category, $user_id)
5384
{
5385
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5386
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5387
            WHERE
5388
                user_id='".intval($user_id)."' AND
5389
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5390
                user_course_cat='".intval($user_course_category)."'";
5391
    $result_max = Database::query($sql);
5392
    if (Database::num_rows($result_max) == 1) {
5393
        $row_max = Database::fetch_array($result_max);
5394
5395
        return $row_max['max_sort'];
5396
    }
5397
5398
    return 0;
5399
}
5400
5401
/**
5402
 * Transforms a number of seconds in hh:mm:ss format.
5403
 *
5404
 * @author Julian Prud'homme
5405
 *
5406
 * @param int    $seconds      number of seconds
5407
 * @param string $space
5408
 * @param bool   $showSeconds
5409
 * @param bool   $roundMinutes
5410
 *
5411
 * @return string the formatted time
5412
 */
5413
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
5414
{
5415
    // $seconds = -1 means that we have wrong data in the db.
5416
    if ($seconds == -1) {
5417
        return
5418
            get_lang('Unknown').
5419
            Display::return_icon(
5420
                'info2.gif',
5421
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5422
                ['align' => 'absmiddle', 'hspace' => '3px']
5423
            );
5424
    }
5425
5426
    // How many hours ?
5427
    $hours = floor($seconds / 3600);
5428
5429
    // How many minutes ?
5430
    $min = floor(($seconds - ($hours * 3600)) / 60);
5431
5432
    if ($roundMinutes) {
5433
        if ($min >= 45) {
5434
            $min = 45;
5435
        }
5436
5437
        if ($min >= 30 && $min <= 44) {
5438
            $min = 30;
5439
        }
5440
5441
        if ($min >= 15 && $min <= 29) {
5442
            $min = 15;
5443
        }
5444
5445
        if ($min >= 0 && $min <= 14) {
5446
            $min = 0;
5447
        }
5448
    }
5449
5450
    // How many seconds
5451
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5452
5453
    if ($hours < 10) {
5454
        $hours = "0$hours";
5455
    }
5456
5457
    if ($sec < 10) {
5458
        $sec = "0$sec";
5459
    }
5460
5461
    if ($min < 10) {
5462
        $min = "0$min";
5463
    }
5464
5465
    $seconds = '';
5466
    if ($showSeconds) {
5467
        $seconds = $space.$sec;
5468
    }
5469
5470
    return $hours.$space.$min.$seconds;
5471
}
5472
5473
/* FILE SYSTEM RELATED FUNCTIONS */
5474
5475
/**
5476
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5477
 * The return value is based on the platform administrator's setting
5478
 * "Administration > Configuration settings > Security > Permissions for new directories".
5479
 *
5480
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5481
 */
5482
function api_get_permissions_for_new_directories()
5483
{
5484
    static $permissions;
5485
    if (!isset($permissions)) {
5486
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5487
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5488
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5489
    }
5490
5491
    return $permissions;
5492
}
5493
5494
/**
5495
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5496
 * The return value is based on the platform administrator's setting
5497
 * "Administration > Configuration settings > Security > Permissions for new files".
5498
 *
5499
 * @return int returns the permissions in the format
5500
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5501
 */
5502
function api_get_permissions_for_new_files()
5503
{
5504
    static $permissions;
5505
    if (!isset($permissions)) {
5506
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5507
        // The default value 0666 is according to that in the platform
5508
        // administration panel after fresh system installation.
5509
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5510
    }
5511
5512
    return $permissions;
5513
}
5514
5515
/**
5516
 * Deletes a file, or a folder and its contents.
5517
 *
5518
 * @author      Aidan Lister <[email protected]>
5519
 *
5520
 * @version     1.0.3
5521
 *
5522
 * @param string $dirname Directory to delete
5523
 * @param       bool     Deletes only the content or not
5524
 * @param bool $strict if one folder/file fails stop the loop
5525
 *
5526
 * @return bool Returns TRUE on success, FALSE on failure
5527
 *
5528
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5529
 *
5530
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5531
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5532
 */
5533
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5534
{
5535
    $res = true;
5536
    // A sanity check.
5537
    if (!file_exists($dirname)) {
5538
        return false;
5539
    }
5540
    $php_errormsg = '';
5541
    // Simple delete for a file.
5542
    if (is_file($dirname) || is_link($dirname)) {
5543
        $res = unlink($dirname);
5544
        if ($res === false) {
5545
            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);
5546
        }
5547
5548
        return $res;
5549
    }
5550
5551
    // Loop through the folder.
5552
    $dir = dir($dirname);
5553
    // A sanity check.
5554
    $is_object_dir = is_object($dir);
5555
    if ($is_object_dir) {
5556
        while (false !== $entry = $dir->read()) {
5557
            // Skip pointers.
5558
            if ($entry == '.' || $entry == '..') {
5559
                continue;
5560
            }
5561
5562
            // Recurse.
5563
            if ($strict) {
5564
                $result = rmdirr("$dirname/$entry");
5565
                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...
5566
                    $res = false;
5567
                    break;
5568
                }
5569
            } else {
5570
                rmdirr("$dirname/$entry");
5571
            }
5572
        }
5573
    }
5574
5575
    // Clean up.
5576
    if ($is_object_dir) {
5577
        $dir->close();
5578
    }
5579
5580
    if ($delete_only_content_in_folder == false) {
5581
        $res = rmdir($dirname);
5582
        if ($res === false) {
5583
            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);
5584
        }
5585
    }
5586
5587
    return $res;
5588
}
5589
5590
// TODO: This function is to be simplified. File access modes to be implemented.
5591
/**
5592
 * function adapted from a php.net comment
5593
 * copy recursively a folder.
5594
 *
5595
 * @param string $source       the source folder
5596
 * @param string $dest         the dest folder
5597
 * @param array  $exclude      an array of excluded file_name (without extension)
5598
 * @param array  $copied_files the returned array of copied files
5599
 */
5600
function copyr($source, $dest, $exclude = [], $copied_files = [])
5601
{
5602
    if (empty($dest)) {
5603
        return false;
5604
    }
5605
    // Simple copy for a file
5606
    if (is_file($source)) {
5607
        $path_info = pathinfo($source);
5608
        if (!in_array($path_info['filename'], $exclude)) {
5609
            copy($source, $dest);
5610
        }
5611
5612
        return true;
5613
    } elseif (!is_dir($source)) {
5614
        //then source is not a dir nor a file, return
5615
        return false;
5616
    }
5617
5618
    // Make destination directory.
5619
    if (!is_dir($dest)) {
5620
        mkdir($dest, api_get_permissions_for_new_directories());
5621
    }
5622
5623
    // Loop through the folder.
5624
    $dir = dir($source);
5625
    while (false !== $entry = $dir->read()) {
5626
        // Skip pointers
5627
        if ($entry == '.' || $entry == '..') {
5628
            continue;
5629
        }
5630
5631
        // Deep copy directories.
5632
        if ($dest !== "$source/$entry") {
5633
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
5634
        }
5635
    }
5636
    // Clean up.
5637
    $dir->close();
5638
5639
    return true;
5640
}
5641
5642
/**
5643
 * @param string $pathname
5644
 * @param string $base_path_document
5645
 * @param int    $session_id
5646
 * @param array
5647
 * @param string
5648
 *
5649
 * @return mixed True if directory already exists, false if a file already exists at
5650
 *               the destination and null if everything goes according to plan
5651
 *@todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5652
 * Documentation header to be added here.
5653
 */
5654
function copy_folder_course_session(
5655
    $pathname,
5656
    $base_path_document,
5657
    $session_id,
5658
    $course_info,
5659
    $document,
5660
    $source_course_id,
5661
    $originalFolderNameList = [],
5662
    $originalBaseName = ''
5663
) {
5664
    // Check whether directory already exists.
5665
    if (empty($pathname) || is_dir($pathname)) {
5666
        return true;
5667
    }
5668
5669
    // Ensure that a file with the same name does not already exist.
5670
    if (is_file($pathname)) {
5671
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5672
5673
        return false;
5674
    }
5675
5676
    //error_log('checking:');
5677
    //error_log(str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5678
    $baseNoDocument = str_replace('document', '', $originalBaseName);
5679
    $folderTitles = explode('/', $baseNoDocument);
5680
    $folderTitles = array_filter($folderTitles);
5681
5682
    //error_log($baseNoDocument);error_log(print_r($folderTitles, 1));
5683
5684
    $table = Database::get_course_table(TABLE_DOCUMENT);
5685
    $session_id = (int) $session_id;
5686
    $source_course_id = (int) $source_course_id;
5687
    $course_id = $course_info['real_id'];
5688
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5689
    $new_pathname = $base_path_document;
5690
5691
    $path = '';
5692
    foreach ($folders as $index => $folder) {
5693
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5694
        $path .= DIRECTORY_SEPARATOR.$folder;
5695
5696
        if (!file_exists($new_pathname)) {
5697
            $path = Database::escape_string($path);
5698
            //error_log("path: $path");
5699
            $sql = "SELECT * FROM $table
5700
                    WHERE
5701
                        c_id = $source_course_id AND
5702
                        path = '$path' AND
5703
                        filetype = 'folder' AND
5704
                        session_id = '$session_id'";
5705
            $rs1 = Database::query($sql);
5706
            $num_rows = Database::num_rows($rs1);
5707
5708
            if (0 == $num_rows) {
5709
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5710
                $title = basename($new_pathname);
5711
5712
                if (isset($folderTitles[$index + 1])) {
5713
                    $checkPath = $folderTitles[$index + 1];
5714
                    //error_log("check $checkPath");
5715
                    if (isset($originalFolderNameList[$checkPath])) {
5716
                        $title = $originalFolderNameList[$checkPath];
5717
                        //error_log('use this name: '.$title);
5718
                    }
5719
                }
5720
5721
                // Insert new folder with destination session_id.
5722
                $params = [
5723
                    'c_id' => $course_id,
5724
                    'path' => $path,
5725
                    'comment' => $document->comment,
5726
                    'title' => $title,
5727
                    'filetype' => 'folder',
5728
                    'size' => '0',
5729
                    'session_id' => $session_id,
5730
                ];
5731
5732
                //error_log("old $folder"); error_log("Add doc $title in $path");
5733
                $document_id = Database::insert($table, $params);
5734
                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...
5735
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5736
                    Database::query($sql);
5737
5738
                    api_item_property_update(
5739
                        $course_info,
5740
                        TOOL_DOCUMENT,
5741
                        $document_id,
5742
                        'FolderCreated',
5743
                        api_get_user_id(),
5744
                        0,
5745
                        0,
5746
                        null,
5747
                        null,
5748
                        $session_id
5749
                    );
5750
                }
5751
            }
5752
        }
5753
    }
5754
}
5755
5756
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5757
/**
5758
 * @param string $path
5759
 */
5760
function api_chmod_R($path, $filemode)
5761
{
5762
    if (!is_dir($path)) {
5763
        return chmod($path, $filemode);
5764
    }
5765
5766
    $handler = opendir($path);
5767
    while ($file = readdir($handler)) {
5768
        if ($file != '.' && $file != '..') {
5769
            $fullpath = "$path/$file";
5770
            if (!is_dir($fullpath)) {
5771
                if (!chmod($fullpath, $filemode)) {
5772
                    return false;
5773
                }
5774
            } else {
5775
                if (!api_chmod_R($fullpath, $filemode)) {
5776
                    return false;
5777
                }
5778
            }
5779
        }
5780
    }
5781
5782
    closedir($handler);
5783
5784
    return chmod($path, $filemode);
5785
}
5786
5787
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5788
/**
5789
 * Parse info file format. (e.g: file.info).
5790
 *
5791
 * Files should use an ini-like format to specify values.
5792
 * White-space generally doesn't matter, except inside values.
5793
 * e.g.
5794
 *
5795
 * @verbatim
5796
 *   key = value
5797
 *   key = "value"
5798
 *   key = 'value'
5799
 *   key = "multi-line
5800
 *
5801
 *   value"
5802
 *   key = 'multi-line
5803
 *
5804
 *   value'
5805
 *   key
5806
 *   =
5807
 *   'value'
5808
 * @endverbatim
5809
 *
5810
 * Arrays are created using a GET-like syntax:
5811
 *
5812
 * @verbatim
5813
 *   key[] = "numeric array"
5814
 *   key[index] = "associative array"
5815
 *   key[index][] = "nested numeric array"
5816
 *   key[index][index] = "nested associative array"
5817
 * @endverbatim
5818
 *
5819
 * PHP constants are substituted in, but only when used as the entire value:
5820
 *
5821
 * Comments should start with a semi-colon at the beginning of a line.
5822
 *
5823
 * This function is NOT for placing arbitrary module-specific settings. Use
5824
 * variable_get() and variable_set() for that.
5825
 *
5826
 * Information stored in the module.info file:
5827
 * - name: The real name of the module for display purposes.
5828
 * - description: A brief description of the module.
5829
 * - dependencies: An array of shortnames of other modules this module depends on.
5830
 * - package: The name of the package of modules this module belongs to.
5831
 *
5832
 * Example of .info file:
5833
 * <code>
5834
 * @verbatim
5835
 *   name = Forum
5836
 *   description = Enables threaded discussions about general topics.
5837
 *   dependencies[] = taxonomy
5838
 *   dependencies[] = comment
5839
 *   package = Core - optional
5840
 *   version = VERSION
5841
 * @endverbatim
5842
 * </code>
5843
 *
5844
 * @param string $filename
5845
 *                         The file we are parsing. Accepts file with relative or absolute path.
5846
 *
5847
 * @return
5848
 *   The info array
5849
 */
5850
function api_parse_info_file($filename)
5851
{
5852
    $info = [];
5853
5854
    if (!file_exists($filename)) {
5855
        return $info;
5856
    }
5857
5858
    $data = file_get_contents($filename);
5859
    if (preg_match_all('
5860
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5861
        ((?:
5862
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5863
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5864
        )+?)
5865
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5866
        (?:
5867
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5868
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5869
          ([^\r\n]*?)                   # Non-quoted string
5870
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5871
        @msx', $data, $matches, PREG_SET_ORDER)) {
5872
        $key = $value1 = $value2 = $value3 = '';
5873
        foreach ($matches as $match) {
5874
            // Fetch the key and value string.
5875
            $i = 0;
5876
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5877
                $$var = isset($match[++$i]) ? $match[$i] : '';
5878
            }
5879
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5880
5881
            // Parse array syntax.
5882
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5883
            $last = array_pop($keys);
5884
            $parent = &$info;
5885
5886
            // Create nested arrays.
5887
            foreach ($keys as $key) {
5888
                if ($key == '') {
5889
                    $key = count($parent);
5890
                }
5891
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5892
                    $parent[$key] = [];
5893
                }
5894
                $parent = &$parent[$key];
5895
            }
5896
5897
            // Handle PHP constants.
5898
            if (defined($value)) {
5899
                $value = constant($value);
5900
            }
5901
5902
            // Insert actual value.
5903
            if ($last == '') {
5904
                $last = count($parent);
5905
            }
5906
            $parent[$last] = $value;
5907
        }
5908
    }
5909
5910
    return $info;
5911
}
5912
5913
/**
5914
 * Gets Chamilo version from the configuration files.
5915
 *
5916
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5917
 */
5918
function api_get_version()
5919
{
5920
    return (string) api_get_configuration_value('system_version');
5921
}
5922
5923
/**
5924
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5925
 *
5926
 * @return string
5927
 */
5928
function api_get_software_name()
5929
{
5930
    $name = api_get_configuration_value('software_name');
5931
    if (!empty($name)) {
5932
        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...
5933
    } else {
5934
        return 'Chamilo';
5935
    }
5936
}
5937
5938
/**
5939
 * Checks whether status given in parameter exists in the platform.
5940
 *
5941
 * @param mixed the status (can be either int either string)
5942
 *
5943
 * @return bool if the status exists, else returns false
5944
 */
5945
function api_status_exists($status_asked)
5946
{
5947
    global $_status_list;
5948
5949
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5950
}
5951
5952
/**
5953
 * Checks whether status given in parameter exists in the platform. The function
5954
 * returns the status ID or false if it does not exist, but given the fact there
5955
 * is no "0" status, the return value can be checked against
5956
 * if(api_status_key()) to know if it exists.
5957
 *
5958
 * @param   mixed   The status (can be either int or string)
5959
 *
5960
 * @return mixed Status ID if exists, false otherwise
5961
 */
5962
function api_status_key($status)
5963
{
5964
    global $_status_list;
5965
5966
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5967
}
5968
5969
/**
5970
 * Gets the status langvars list.
5971
 *
5972
 * @return string[] the list of status with their translations
5973
 */
5974
function api_get_status_langvars()
5975
{
5976
    return [
5977
        COURSEMANAGER => get_lang('Teacher', ''),
5978
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5979
        DRH => get_lang('Drh', ''),
5980
        STUDENT => get_lang('Student', ''),
5981
        ANONYMOUS => get_lang('Anonymous', ''),
5982
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5983
        INVITEE => get_lang('Invited'),
5984
    ];
5985
}
5986
5987
/**
5988
 * The function that retrieves all the possible settings for a certain config setting.
5989
 *
5990
 * @author Patrick Cool <[email protected]>, Ghent University
5991
 */
5992
function api_get_settings_options($var)
5993
{
5994
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5995
    $var = Database::escape_string($var);
5996
    $sql = "SELECT * FROM $table_settings_options
5997
            WHERE variable = '$var'
5998
            ORDER BY id";
5999
    $result = Database::query($sql);
6000
    $settings_options_array = [];
6001
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6002
        $settings_options_array[] = $row;
6003
    }
6004
6005
    return $settings_options_array;
6006
}
6007
6008
/**
6009
 * @param array $params
6010
 */
6011
function api_set_setting_option($params)
6012
{
6013
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6014
    if (empty($params['id'])) {
6015
        Database::insert($table, $params);
6016
    } else {
6017
        Database::update($table, $params, ['id = ? ' => $params['id']]);
6018
    }
6019
}
6020
6021
/**
6022
 * @param array $params
6023
 */
6024
function api_set_setting_simple($params)
6025
{
6026
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6027
    $url_id = api_get_current_access_url_id();
6028
6029
    if (empty($params['id'])) {
6030
        $params['access_url'] = $url_id;
6031
        Database::insert($table, $params);
6032
    } else {
6033
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
6034
    }
6035
}
6036
6037
/**
6038
 * @param int $id
6039
 */
6040
function api_delete_setting_option($id)
6041
{
6042
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6043
    if (!empty($id)) {
6044
        Database::delete($table, ['id = ? ' => $id]);
6045
    }
6046
}
6047
6048
/**
6049
 * Sets a platform configuration setting to a given value.
6050
 *
6051
 * @param string    The variable we want to update
6052
 * @param string    The value we want to record
6053
 * @param string    The sub-variable if any (in most cases, this will remain null)
6054
 * @param string    The category if any (in most cases, this will remain null)
6055
 * @param int       The access_url for which this parameter is valid
6056
 * @param string $cat
6057
 *
6058
 * @return bool|null
6059
 */
6060
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
6061
{
6062
    if (empty($var)) {
6063
        return false;
6064
    }
6065
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6066
    $var = Database::escape_string($var);
6067
    $value = Database::escape_string($value);
6068
    $access_url = (int) $access_url;
6069
    if (empty($access_url)) {
6070
        $access_url = 1;
6071
    }
6072
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
6073
    if (!empty($subvar)) {
6074
        $subvar = Database::escape_string($subvar);
6075
        $select .= " AND subkey = '$subvar'";
6076
    }
6077
    if (!empty($cat)) {
6078
        $cat = Database::escape_string($cat);
6079
        $select .= " AND category = '$cat'";
6080
    }
6081
    if ($access_url > 1) {
6082
        $select .= " AND access_url = $access_url";
6083
    } else {
6084
        $select .= " AND access_url = 1 ";
6085
    }
6086
6087
    $res = Database::query($select);
6088
    if (Database::num_rows($res) > 0) {
6089
        // Found item for this access_url.
6090
        $row = Database::fetch_array($res);
6091
        $sql = "UPDATE $t_settings SET selected_value = '$value'
6092
                WHERE id = ".$row['id'];
6093
        Database::query($sql);
6094
    } else {
6095
        // Item not found for this access_url, we have to check if it exist with access_url = 1
6096
        $select = "SELECT * FROM $t_settings
6097
                   WHERE variable = '$var' AND access_url = 1 ";
6098
        // Just in case
6099
        if ($access_url == 1) {
6100
            if (!empty($subvar)) {
6101
                $select .= " AND subkey = '$subvar'";
6102
            }
6103
            if (!empty($cat)) {
6104
                $select .= " AND category = '$cat'";
6105
            }
6106
            $res = Database::query($select);
6107
            if (Database::num_rows($res) > 0) {
6108
                // We have a setting for access_url 1, but none for the current one, so create one.
6109
                $row = Database::fetch_array($res);
6110
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
6111
                        VALUES
6112
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6113
                        "'".$row['type']."','".$row['category']."',".
6114
                        "'$value','".$row['title']."',".
6115
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6116
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
6117
                Database::query($insert);
6118
            } else {
6119
                // Such a setting does not exist.
6120
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
6121
            }
6122
        } else {
6123
            // Other access url.
6124
            if (!empty($subvar)) {
6125
                $select .= " AND subkey = '$subvar'";
6126
            }
6127
            if (!empty($cat)) {
6128
                $select .= " AND category = '$cat'";
6129
            }
6130
            $res = Database::query($select);
6131
6132
            if (Database::num_rows($res) > 0) {
6133
                // We have a setting for access_url 1, but none for the current one, so create one.
6134
                $row = Database::fetch_array($res);
6135
                if ($row['access_url_changeable'] == 1) {
6136
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
6137
                            ('".$row['variable']."',".
6138
                            (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6139
                            "'".$row['type']."','".$row['category']."',".
6140
                            "'$value','".$row['title']."',".
6141
                            "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
6142
                            (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6143
                            "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
6144
                    Database::query($insert);
6145
                }
6146
            } else { // Such a setting does not exist.
6147
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
6148
            }
6149
        }
6150
    }
6151
}
6152
6153
/**
6154
 * Sets a whole category of settings to one specific value.
6155
 *
6156
 * @param string    Category
6157
 * @param string    Value
6158
 * @param int       Access URL. Optional. Defaults to 1
6159
 * @param array     Optional array of filters on field type
6160
 * @param string $category
6161
 * @param string $value
6162
 *
6163
 * @return bool
6164
 */
6165
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
6166
{
6167
    if (empty($category)) {
6168
        return false;
6169
    }
6170
    $category = Database::escape_string($category);
6171
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6172
    $access_url = (int) $access_url;
6173
    if (empty($access_url)) {
6174
        $access_url = 1;
6175
    }
6176
    if (isset($value)) {
6177
        $value = Database::escape_string($value);
6178
        $sql = "UPDATE $t_s SET selected_value = '$value'
6179
                WHERE category = '$category' AND access_url = $access_url";
6180
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6181
            $sql .= " AND ( ";
6182
            $i = 0;
6183
            foreach ($fieldtype as $type) {
6184
                if ($i > 0) {
6185
                    $sql .= ' OR ';
6186
                }
6187
                $type = Database::escape_string($type);
6188
                $sql .= " type='".$type."' ";
6189
                $i++;
6190
            }
6191
            $sql .= ")";
6192
        }
6193
        $res = Database::query($sql);
6194
6195
        return $res !== false;
6196
    } else {
6197
        $sql = "UPDATE $t_s SET selected_value = NULL
6198
                WHERE category = '$category' AND access_url = $access_url";
6199
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6200
            $sql .= " AND ( ";
6201
            $i = 0;
6202
            foreach ($fieldtype as $type) {
6203
                if ($i > 0) {
6204
                    $sql .= ' OR ';
6205
                }
6206
                $type = Database::escape_string($type);
6207
                $sql .= " type='".$type."' ";
6208
                $i++;
6209
            }
6210
            $sql .= ")";
6211
        }
6212
        $res = Database::query($sql);
6213
6214
        return $res !== false;
6215
    }
6216
}
6217
6218
/**
6219
 * Gets all available access urls in an array (as in the database).
6220
 *
6221
 * @return array An array of database records
6222
 */
6223
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
6224
{
6225
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6226
    $from = (int) $from;
6227
    $to = (int) $to;
6228
    $order = Database::escape_string($order);
6229
    $direction = Database::escape_string($direction);
6230
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
6231
6232
    $sql = "SELECT id, url, description, active, created_by, tms
6233
            FROM $table
6234
            ORDER BY `$order` $direction
6235
            LIMIT $to OFFSET $from";
6236
    $res = Database::query($sql);
6237
6238
    return Database::store_result($res);
6239
}
6240
6241
/**
6242
 * Gets the access url info in an array.
6243
 *
6244
 * @param int  $id            Id of the access url
6245
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
6246
 *
6247
 * @return array All the info (url, description, active, created_by, tms)
6248
 *               from the access_url table
6249
 *
6250
 * @author Julio Montoya
6251
 */
6252
function api_get_access_url($id, $returnDefault = true)
6253
{
6254
    static $staticResult;
6255
    $id = (int) $id;
6256
6257
    if (isset($staticResult[$id])) {
6258
        $result = $staticResult[$id];
6259
    } else {
6260
        // Calling the Database:: library dont work this is handmade.
6261
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6262
        $sql = "SELECT url, description, active, created_by, tms
6263
                FROM $table_access_url WHERE id = '$id' ";
6264
        $res = Database::query($sql);
6265
        $result = @Database::fetch_array($res);
6266
        $staticResult[$id] = $result;
6267
    }
6268
6269
    // If the result url is 'http://localhost/' (the default) and the root_web
6270
    // (=current url) is different, and the $id is = 1 (which might mean
6271
    // api_get_current_access_url_id() returned 1 by default), then return the
6272
    // root_web setting instead of the current URL
6273
    // This is provided as an option to avoid breaking the storage of URL-specific
6274
    // homepages in home/localhost/
6275
    if ($id === 1 && $returnDefault === false) {
6276
        $currentUrl = api_get_current_access_url_id();
6277
        // only do this if we are on the main URL (=1), otherwise we could get
6278
        // information on another URL instead of the one asked as parameter
6279
        if ($currentUrl === 1) {
6280
            $rootWeb = api_get_path(WEB_PATH);
6281
            $default = 'http://localhost/';
6282
            if ($result['url'] === $default && $rootWeb != $default) {
6283
                $result['url'] = $rootWeb;
6284
            }
6285
        }
6286
    }
6287
6288
    return $result;
6289
}
6290
6291
/**
6292
 * Gets all the current settings for a specific access url.
6293
 *
6294
 * @param string    The category, if any, that we want to get
6295
 * @param string    Whether we want a simple list (display a category) or
6296
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
6297
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
6298
 *
6299
 * @return array Array of database results for the current settings of the current access URL
6300
 */
6301
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
6302
{
6303
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6304
    $access_url = (int) $access_url;
6305
    $where_condition = '';
6306
    if ($url_changeable == 1) {
6307
        $where_condition = " AND access_url_changeable= '1' ";
6308
    }
6309
    if (empty($access_url) || $access_url == -1) {
6310
        $access_url = 1;
6311
    }
6312
    $sql = "SELECT * FROM $table
6313
            WHERE access_url = $access_url  $where_condition ";
6314
6315
    if (!empty($cat)) {
6316
        $cat = Database::escape_string($cat);
6317
        $sql .= " AND category='$cat' ";
6318
    }
6319
    if ($ordering == 'group') {
6320
        $sql .= " ORDER BY id ASC";
6321
    } else {
6322
        $sql .= " ORDER BY 1,2 ASC";
6323
    }
6324
    $result = Database::query($sql);
6325
    if ($result === null) {
6326
        return [];
6327
    }
6328
    $result = Database::store_result($result, 'ASSOC');
6329
6330
    return $result;
6331
}
6332
6333
/**
6334
 * @param string $value       The value we want to record
6335
 * @param string $variable    The variable name we want to insert
6336
 * @param string $subKey      The subkey for the variable we want to insert
6337
 * @param string $type        The type for the variable we want to insert
6338
 * @param string $category    The category for the variable we want to insert
6339
 * @param string $title       The title
6340
 * @param string $comment     The comment
6341
 * @param string $scope       The scope
6342
 * @param string $subKeyText  The subkey text
6343
 * @param int    $accessUrlId The access_url for which this parameter is valid
6344
 * @param int    $visibility  The changeability of this setting for non-master urls
6345
 *
6346
 * @return int The setting ID
6347
 */
6348
function api_add_setting(
6349
    $value,
6350
    $variable,
6351
    $subKey = '',
6352
    $type = 'textfield',
6353
    $category = '',
6354
    $title = '',
6355
    $comment = '',
6356
    $scope = '',
6357
    $subKeyText = '',
6358
    $accessUrlId = 1,
6359
    $visibility = 0
6360
) {
6361
    $em = Database::getManager();
6362
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6363
    $accessUrlId = (int) $accessUrlId ?: 1;
6364
6365
    if (is_array($value)) {
6366
        $value = serialize($value);
6367
    } else {
6368
        $value = trim($value);
6369
    }
6370
6371
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
6372
6373
    if (!empty($subKey)) {
6374
        $criteria['subkey'] = $subKey;
6375
    }
6376
6377
    // Check if this variable doesn't exist already
6378
    /** @var SettingsCurrent $setting */
6379
    $setting = $settingRepo->findOneBy($criteria);
6380
6381
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
6382
        $setting->setSelectedValue($value);
6383
6384
        $em->persist($setting);
6385
        $em->flush();
6386
6387
        return $setting->getId();
6388
    }
6389
6390
    // Item not found for this access_url, we have to check if the whole thing is missing
6391
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6392
    $setting = new SettingsCurrent();
6393
    $setting
6394
        ->setVariable($variable)
6395
        ->setSelectedValue($value)
6396
        ->setType($type)
6397
        ->setCategory($category)
6398
        ->setSubkey($subKey)
6399
        ->setTitle($title)
6400
        ->setComment($comment)
6401
        ->setScope($scope)
6402
        ->setSubkeytext($subKeyText)
6403
        ->setAccessUrl($accessUrlId)
6404
        ->setAccessUrlChangeable($visibility);
6405
6406
    $em->persist($setting);
6407
    $em->flush();
6408
6409
    return $setting->getId();
6410
}
6411
6412
/**
6413
 * Checks wether a user can or can't view the contents of a course.
6414
 *
6415
 * @deprecated use CourseManager::is_user_subscribed_in_course
6416
 *
6417
 * @param int $userid User id or NULL to get it from $_SESSION
6418
 * @param int $cid    course id to check whether the user is allowed
6419
 *
6420
 * @return bool
6421
 */
6422
function api_is_course_visible_for_user($userid = null, $cid = null)
6423
{
6424
    if ($userid === null) {
6425
        $userid = api_get_user_id();
6426
    }
6427
    if (empty($userid) || strval(intval($userid)) != $userid) {
6428
        if (api_is_anonymous()) {
6429
            $userid = api_get_anonymous_id();
6430
        } else {
6431
            return false;
6432
        }
6433
    }
6434
    $cid = Database::escape_string($cid);
6435
6436
    $courseInfo = api_get_course_info($cid);
6437
    $courseId = $courseInfo['real_id'];
6438
    $is_platformAdmin = api_is_platform_admin();
6439
6440
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6441
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6442
6443
    $sql = "SELECT
6444
                $course_table.category_code,
6445
                $course_table.visibility,
6446
                $course_table.code,
6447
                $course_cat_table.code
6448
            FROM $course_table
6449
            LEFT JOIN $course_cat_table
6450
                ON $course_table.category_code = $course_cat_table.code
6451
            WHERE
6452
                $course_table.code = '$cid'
6453
            LIMIT 1";
6454
6455
    $result = Database::query($sql);
6456
6457
    if (Database::num_rows($result) > 0) {
6458
        $visibility = Database::fetch_array($result);
6459
        $visibility = $visibility['visibility'];
6460
    } else {
6461
        $visibility = 0;
6462
    }
6463
    // Shortcut permissions in case the visibility is "open to the world".
6464
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
6465
        return true;
6466
    }
6467
6468
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6469
6470
    $sql = "SELECT
6471
                is_tutor, status
6472
            FROM $tbl_course_user
6473
            WHERE
6474
                user_id  = '$userid' AND
6475
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6476
                c_id = $courseId
6477
            LIMIT 1";
6478
6479
    $result = Database::query($sql);
6480
6481
    if (Database::num_rows($result) > 0) {
6482
        // This user has got a recorded state for this course.
6483
        $cuData = Database::fetch_array($result);
6484
        $is_courseMember = true;
6485
        $is_courseAdmin = ($cuData['status'] == 1);
6486
    }
6487
6488
    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...
6489
        // This user has no status related to this course.
6490
        // Is it the session coach or the session admin?
6491
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6492
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6493
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6494
6495
        $sql = "SELECT
6496
                    session.id_coach, session_admin_id, session.id
6497
                FROM
6498
                    $tbl_session as session
6499
                INNER JOIN $tbl_session_course
6500
                    ON session_rel_course.session_id = session.id
6501
                    AND session_rel_course.c_id = '$courseId'
6502
                LIMIT 1";
6503
6504
        $result = Database::query($sql);
6505
        $row = Database::store_result($result);
6506
6507
        if ($row[0]['id_coach'] == $userid) {
6508
            $is_courseMember = true;
6509
            $is_courseAdmin = false;
6510
        } elseif ($row[0]['session_admin_id'] == $userid) {
6511
            $is_courseMember = false;
6512
            $is_courseAdmin = false;
6513
        } else {
6514
            // Check if the current user is the course coach.
6515
            $sql = "SELECT 1
6516
                    FROM $tbl_session_course
6517
                    WHERE session_rel_course.c_id = '$courseId'
6518
                    AND session_rel_course.id_coach = '$userid'
6519
                    LIMIT 1";
6520
6521
            $result = Database::query($sql);
6522
6523
            //if ($row = Database::fetch_array($result)) {
6524
            if (Database::num_rows($result) > 0) {
6525
                $is_courseMember = true;
6526
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6527
6528
                $sql = "SELECT status FROM $tbl_user
6529
                        WHERE user_id = $userid
6530
                        LIMIT 1";
6531
6532
                $result = Database::query($sql);
6533
6534
                if (Database::result($result, 0, 0) == 1) {
6535
                    $is_courseAdmin = true;
6536
                } else {
6537
                    $is_courseAdmin = false;
6538
                }
6539
            } else {
6540
                // Check if the user is a student is this session.
6541
                $sql = "SELECT  id
6542
                        FROM $tbl_session_course_user
6543
                        WHERE
6544
                            user_id  = '$userid' AND
6545
                            c_id = '$courseId'
6546
                        LIMIT 1";
6547
6548
                if (Database::num_rows($result) > 0) {
6549
                    // This user haa got a recorded state for this course.
6550
                    while ($row = Database::fetch_array($result)) {
6551
                        $is_courseMember = true;
6552
                        $is_courseAdmin = false;
6553
                    }
6554
                }
6555
            }
6556
        }
6557
    }
6558
6559
    switch ($visibility) {
6560
        case COURSE_VISIBILITY_OPEN_WORLD:
6561
            return true;
6562
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6563
            return isset($userid);
6564
        case COURSE_VISIBILITY_REGISTERED:
6565
        case COURSE_VISIBILITY_CLOSED:
6566
            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...
6567
        case COURSE_VISIBILITY_HIDDEN:
6568
            return $is_platformAdmin;
6569
    }
6570
6571
    return false;
6572
}
6573
6574
/**
6575
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6576
 *
6577
 * @param string the tool of the element
6578
 * @param int the element id in database
6579
 * @param int the session_id to compare with element session id
6580
 *
6581
 * @return bool true if the element is in the session, false else
6582
 */
6583
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6584
{
6585
    if (is_null($session_id)) {
6586
        $session_id = api_get_session_id();
6587
    }
6588
6589
    $element_id = (int) $element_id;
6590
6591
    if (empty($element_id)) {
6592
        return false;
6593
    }
6594
6595
    // Get information to build query depending of the tool.
6596
    switch ($tool) {
6597
        case TOOL_SURVEY:
6598
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6599
            $key_field = 'survey_id';
6600
            break;
6601
        case TOOL_ANNOUNCEMENT:
6602
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6603
            $key_field = 'id';
6604
            break;
6605
        case TOOL_AGENDA:
6606
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6607
            $key_field = 'id';
6608
            break;
6609
        case TOOL_GROUP:
6610
            $table_tool = Database::get_course_table(TABLE_GROUP);
6611
            $key_field = 'id';
6612
            break;
6613
        default:
6614
            return false;
6615
    }
6616
    $course_id = api_get_course_int_id();
6617
6618
    $sql = "SELECT session_id FROM $table_tool
6619
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6620
    $rs = Database::query($sql);
6621
    if ($element_session_id = Database::result($rs, 0, 0)) {
6622
        if ($element_session_id == intval($session_id)) {
6623
            // The element belongs to the session.
6624
            return true;
6625
        }
6626
    }
6627
6628
    return false;
6629
}
6630
6631
/**
6632
 * Replaces "forbidden" characters in a filename string.
6633
 *
6634
 * @param string $filename
6635
 * @param bool   $treat_spaces_as_hyphens
6636
 *
6637
 * @return string
6638
 */
6639
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6640
{
6641
    // Some non-properly encoded file names can cause the whole file to be
6642
    // skipped when uploaded. Avoid this by detecting the encoding and
6643
    // converting to UTF-8, setting the source as ASCII (a reasonably
6644
    // limited characters set) if nothing could be found (BT#
6645
    $encoding = api_detect_encoding($filename);
6646
    if (empty($encoding)) {
6647
        $encoding = 'ASCII';
6648
        if (!api_is_valid_ascii($filename)) {
6649
            // try iconv and try non standard ASCII a.k.a CP437
6650
            // see BT#15022
6651
            if (function_exists('iconv')) {
6652
                $result = iconv('CP437', 'UTF-8', $filename);
6653
                if (api_is_valid_utf8($result)) {
6654
                    $filename = $result;
6655
                    $encoding = 'UTF-8';
6656
                }
6657
            }
6658
        }
6659
    }
6660
6661
    $filename = api_to_system_encoding($filename, $encoding);
6662
6663
    $url = URLify::filter(
6664
        $filename,
6665
        250,
6666
        '',
6667
        true,
6668
        false,
6669
        false,
6670
        false,
6671
        $treat_spaces_as_hyphens
6672
    );
6673
6674
    // Replace multiple dots at the end.
6675
    $regex = "/\.+$/";
6676
    $url = preg_replace($regex, '', $url);
6677
6678
    return $url;
6679
}
6680
6681
/**
6682
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6683
 *
6684
 * @author Ivan Tcholakov, 28-JUN-2006.
6685
 */
6686
function api_request_uri()
6687
{
6688
    if (!empty($_SERVER['REQUEST_URI'])) {
6689
        return $_SERVER['REQUEST_URI'];
6690
    }
6691
    $uri = $_SERVER['SCRIPT_NAME'];
6692
    if (!empty($_SERVER['QUERY_STRING'])) {
6693
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6694
    }
6695
    $_SERVER['REQUEST_URI'] = $uri;
6696
6697
    return $uri;
6698
}
6699
6700
/**
6701
 * Gets the current access_url id of the Chamilo Platform.
6702
 *
6703
 * @return int access_url_id of the current Chamilo Installation or 1 if multiple_access_urls is not enabled
6704
 *
6705
 * @author Julio Montoya <[email protected]>
6706
 */
6707
function api_get_current_access_url_id()
6708
{
6709
    if ('cli' === PHP_SAPI) {
6710
        $accessUrlId = api_get_configuration_value('access_url');
6711
        if (!empty($accessUrlId)) {
6712
            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...
6713
        }
6714
    }
6715
6716
    static $id;
6717
    if (!empty($id)) {
6718
        return (int) $id;
6719
    }
6720
6721
    if (!api_get_multiple_access_url()) {
6722
        // If the feature is not enabled, assume 1 and return before querying
6723
        // the database
6724
        return 1;
6725
    }
6726
6727
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6728
    $path = Database::escape_string(api_get_path(WEB_PATH));
6729
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6730
    $result = Database::query($sql);
6731
    if (Database::num_rows($result) > 0) {
6732
        $id = Database::result($result, 0, 0);
6733
        if ($id === false) {
6734
            return -1;
6735
        }
6736
6737
        return (int) $id;
6738
    }
6739
6740
    $id = 1;
6741
6742
    //if the url in WEB_PATH was not found, it can only mean that there is
6743
    // either a configuration problem or the first URL has not been defined yet
6744
    // (by default it is http://localhost/). Thus the more sensible thing we can
6745
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6746
    return 1;
6747
}
6748
6749
/**
6750
 * Gets the registered urls from a given user id.
6751
 *
6752
 * @param int $user_id
6753
 *
6754
 * @return array
6755
 *
6756
 * @author Julio Montoya <[email protected]>
6757
 */
6758
function api_get_access_url_from_user($user_id)
6759
{
6760
    $user_id = (int) $user_id;
6761
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6762
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6763
    $sql = "SELECT access_url_id
6764
            FROM $table_url_rel_user url_rel_user
6765
            INNER JOIN $table_url u
6766
            ON (url_rel_user.access_url_id = u.id)
6767
            WHERE user_id = ".intval($user_id);
6768
    $result = Database::query($sql);
6769
    $list = [];
6770
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6771
        $list[] = $row['access_url_id'];
6772
    }
6773
6774
    return $list;
6775
}
6776
6777
/**
6778
 * Gets the status of a user in a course.
6779
 *
6780
 * @param int $user_id
6781
 * @param int $courseId
6782
 *
6783
 * @return int user status
6784
 */
6785
function api_get_status_of_user_in_course($user_id, $courseId)
6786
{
6787
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6788
    if (!empty($user_id) && !empty($courseId)) {
6789
        $user_id = intval($user_id);
6790
        $courseId = intval($courseId);
6791
        $sql = 'SELECT status
6792
                FROM '.$tbl_rel_course_user.'
6793
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6794
        $result = Database::query($sql);
6795
        $row_status = Database::fetch_array($result, 'ASSOC');
6796
6797
        return $row_status['status'];
6798
    } else {
6799
        return 0;
6800
    }
6801
}
6802
6803
/**
6804
 * Checks whether the curent user is in a group or not.
6805
 *
6806
 * @param string        The group id - optional (takes it from session if not given)
6807
 * @param string        The course code - optional (no additional check by course if course code is not given)
6808
 *
6809
 * @return bool
6810
 *
6811
 * @author Ivan Tcholakov
6812
 */
6813
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6814
{
6815
    if (!empty($courseCodeParam)) {
6816
        $courseCode = api_get_course_id();
6817
        if (!empty($courseCode)) {
6818
            if ($courseCodeParam != $courseCode) {
6819
                return false;
6820
            }
6821
        } else {
6822
            return false;
6823
        }
6824
    }
6825
6826
    $groupId = api_get_group_id();
6827
6828
    if (!empty($groupId)) {
6829
        if (!empty($groupIdParam)) {
6830
            return $groupIdParam == $groupId;
6831
        } else {
6832
            return true;
6833
        }
6834
    }
6835
6836
    return false;
6837
}
6838
6839
/**
6840
 * Checks whether a secret key is valid.
6841
 *
6842
 * @param string $original_key_secret - secret key from (webservice) client
6843
 * @param string $security_key        - security key from Chamilo
6844
 *
6845
 * @return bool - true if secret key is valid, false otherwise
6846
 */
6847
function api_is_valid_secret_key($original_key_secret, $security_key)
6848
{
6849
    if (empty($original_key_secret) || empty($security_key)) {
6850
        return false;
6851
    }
6852
6853
    return (string) $original_key_secret === sha1($security_key);
6854
}
6855
6856
/**
6857
 * Checks whether a user is into course.
6858
 *
6859
 * @param int $course_id - the course id
6860
 * @param int $user_id   - the user id
6861
 *
6862
 * @return bool
6863
 */
6864
function api_is_user_of_course($course_id, $user_id)
6865
{
6866
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6867
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6868
            WHERE
6869
                c_id ="'.intval($course_id).'" AND
6870
                user_id = "'.intval($user_id).'" AND
6871
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6872
    $result = Database::query($sql);
6873
6874
    return Database::num_rows($result) == 1;
6875
}
6876
6877
/**
6878
 * Checks whether the server's operating system is Windows (TM).
6879
 *
6880
 * @return bool - true if the operating system is Windows, false otherwise
6881
 */
6882
function api_is_windows_os()
6883
{
6884
    if (function_exists('php_uname')) {
6885
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6886
        // We expect that this function will always work for Chamilo 1.8.x.
6887
        $os = php_uname();
6888
    }
6889
    // The following methods are not needed, but let them stay, just in case.
6890
    elseif (isset($_ENV['OS'])) {
6891
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6892
        $os = $_ENV['OS'];
6893
    } elseif (defined('PHP_OS')) {
6894
        // PHP_OS means on which OS PHP was compiled, this is why
6895
        // using PHP_OS is the last choice for detection.
6896
        $os = PHP_OS;
6897
    } else {
6898
        return false;
6899
    }
6900
6901
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6902
}
6903
6904
/**
6905
 * This function informs whether the sent request is XMLHttpRequest.
6906
 */
6907
function api_is_xml_http_request()
6908
{
6909
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6910
}
6911
6912
/**
6913
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6914
 *
6915
 * @see http://php.net/manual/en/function.getimagesize.php
6916
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6917
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6918
 *
6919
 * @return int
6920
 */
6921
function api_getimagesize($path)
6922
{
6923
    $image = new Image($path);
6924
6925
    return $image->get_image_size();
6926
}
6927
6928
/**
6929
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6930
 *
6931
 * @author Ivan Tcholakov, MAY-2009.
6932
 *
6933
 * @param int $image         System path or URL of the image
6934
 * @param int $target_width  Targeted width
6935
 * @param int $target_height Targeted height
6936
 *
6937
 * @return array Calculated new width and height
6938
 */
6939
function api_resize_image($image, $target_width, $target_height)
6940
{
6941
    $image_properties = api_getimagesize($image);
6942
6943
    return api_calculate_image_size(
6944
        $image_properties['width'],
6945
        $image_properties['height'],
6946
        $target_width,
6947
        $target_height
6948
    );
6949
}
6950
6951
/**
6952
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6953
 *
6954
 * @author Ivan Tcholakov, MAY-2009.
6955
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6956
 *
6957
 * @param int $image_width   Initial width
6958
 * @param int $image_height  Initial height
6959
 * @param int $target_width  Targeted width
6960
 * @param int $target_height Targeted height
6961
 *
6962
 * @return array Calculated new width and height
6963
 */
6964
function api_calculate_image_size(
6965
    $image_width,
6966
    $image_height,
6967
    $target_width,
6968
    $target_height
6969
) {
6970
    // Only maths is here.
6971
    $result = ['width' => $image_width, 'height' => $image_height];
6972
    if ($image_width <= 0 || $image_height <= 0) {
6973
        return $result;
6974
    }
6975
    $resize_factor_width = $target_width / $image_width;
6976
    $resize_factor_height = $target_height / $image_height;
6977
    $delta_width = $target_width - $image_width * $resize_factor_height;
6978
    $delta_height = $target_height - $image_height * $resize_factor_width;
6979
    if ($delta_width > $delta_height) {
6980
        $result['width'] = ceil($image_width * $resize_factor_height);
6981
        $result['height'] = ceil($image_height * $resize_factor_height);
6982
    } elseif ($delta_width < $delta_height) {
6983
        $result['width'] = ceil($image_width * $resize_factor_width);
6984
        $result['height'] = ceil($image_height * $resize_factor_width);
6985
    } else {
6986
        $result['width'] = ceil($target_width);
6987
        $result['height'] = ceil($target_height);
6988
    }
6989
6990
    return $result;
6991
}
6992
6993
/**
6994
 * Returns a list of Chamilo's tools or
6995
 * checks whether a given identificator is a valid Chamilo's tool.
6996
 *
6997
 * @author Isaac flores paz
6998
 *
6999
 * @param string The tool name to filter
7000
 *
7001
 * @return mixed Filtered string or array
7002
 */
7003
function api_get_tools_lists($my_tool = null)
7004
{
7005
    $tools_list = [
7006
        TOOL_DOCUMENT,
7007
        TOOL_THUMBNAIL,
7008
        TOOL_HOTPOTATOES,
7009
        TOOL_CALENDAR_EVENT,
7010
        TOOL_LINK,
7011
        TOOL_COURSE_DESCRIPTION,
7012
        TOOL_SEARCH,
7013
        TOOL_LEARNPATH,
7014
        TOOL_ANNOUNCEMENT,
7015
        TOOL_FORUM,
7016
        TOOL_THREAD,
7017
        TOOL_POST,
7018
        TOOL_DROPBOX,
7019
        TOOL_QUIZ,
7020
        TOOL_USER,
7021
        TOOL_GROUP,
7022
        TOOL_BLOGS,
7023
        TOOL_CHAT,
7024
        TOOL_STUDENTPUBLICATION,
7025
        TOOL_TRACKING,
7026
        TOOL_HOMEPAGE_LINK,
7027
        TOOL_COURSE_SETTING,
7028
        TOOL_BACKUP,
7029
        TOOL_COPY_COURSE_CONTENT,
7030
        TOOL_RECYCLE_COURSE,
7031
        TOOL_COURSE_HOMEPAGE,
7032
        TOOL_COURSE_RIGHTS_OVERVIEW,
7033
        TOOL_UPLOAD,
7034
        TOOL_COURSE_MAINTENANCE,
7035
        TOOL_SURVEY,
7036
        TOOL_WIKI,
7037
        TOOL_GLOSSARY,
7038
        TOOL_GRADEBOOK,
7039
        TOOL_NOTEBOOK,
7040
        TOOL_ATTENDANCE,
7041
        TOOL_COURSE_PROGRESS,
7042
    ];
7043
    if (empty($my_tool)) {
7044
        return $tools_list;
7045
    }
7046
7047
    return in_array($my_tool, $tools_list) ? $my_tool : '';
7048
}
7049
7050
/**
7051
 * Checks whether we already approved the last version term and condition.
7052
 *
7053
 * @param int user id
7054
 *
7055
 * @return bool true if we pass false otherwise
7056
 */
7057
function api_check_term_condition($userId)
7058
{
7059
    if (api_get_setting('allow_terms_conditions') === 'true') {
7060
        // Check if exists terms and conditions
7061
        if (LegalManager::count() == 0) {
7062
            return true;
7063
        }
7064
7065
        $extraFieldValue = new ExtraFieldValue('user');
7066
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
7067
            $userId,
7068
            'legal_accept'
7069
        );
7070
7071
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
7072
            $result = $data['value'];
7073
            $user_conditions = explode(':', $result);
7074
            $version = $user_conditions[0];
7075
            $langId = $user_conditions[1];
7076
            $realVersion = LegalManager::get_last_version($langId);
7077
7078
            return $version >= $realVersion;
7079
        }
7080
7081
        return false;
7082
    }
7083
7084
    return false;
7085
}
7086
7087
/**
7088
 * Gets all information of a tool into course.
7089
 *
7090
 * @param int The tool id
7091
 *
7092
 * @return array
7093
 */
7094
function api_get_tool_information_by_name($name)
7095
{
7096
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
7097
    $course_id = api_get_course_int_id();
7098
    $sql = "SELECT * FROM $t_tool
7099
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
7100
    $rs = Database::query($sql);
7101
7102
    return Database::fetch_array($rs, 'ASSOC');
7103
}
7104
7105
/**
7106
 * Function used to protect a "global" admin script.
7107
 * The function blocks access when the user has no global platform admin rights.
7108
 * Global admins are the admins that are registered in the main.admin table
7109
 * AND the users who have access to the "principal" portal.
7110
 * That means that there is a record in the main.access_url_rel_user table
7111
 * with his user id and the access_url_id=1.
7112
 *
7113
 * @author Julio Montoya
7114
 *
7115
 * @param int $user_id
7116
 *
7117
 * @return bool
7118
 */
7119
function api_is_global_platform_admin($user_id = null)
7120
{
7121
    $user_id = (int) $user_id;
7122
    if (empty($user_id)) {
7123
        $user_id = api_get_user_id();
7124
    }
7125
    if (api_is_platform_admin_by_id($user_id)) {
7126
        $urlList = api_get_access_url_from_user($user_id);
7127
        // The admin is registered in the first "main" site with access_url_id = 1
7128
        if (in_array(1, $urlList)) {
7129
            return true;
7130
        } else {
7131
            return false;
7132
        }
7133
    }
7134
7135
    return false;
7136
}
7137
7138
/**
7139
 * @param int  $admin_id_to_check
7140
 * @param int  $my_user_id
7141
 * @param bool $allow_session_admin
7142
 *
7143
 * @return bool
7144
 */
7145
function api_global_admin_can_edit_admin(
7146
    $admin_id_to_check,
7147
    $my_user_id = null,
7148
    $allow_session_admin = false
7149
) {
7150
    if (empty($my_user_id)) {
7151
        $my_user_id = api_get_user_id();
7152
    }
7153
7154
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
7155
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
7156
7157
    if ($iam_a_global_admin) {
7158
        // Global admin can edit everything
7159
        return true;
7160
    } else {
7161
        // If i'm a simple admin
7162
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
7163
7164
        if ($allow_session_admin) {
7165
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
7166
        }
7167
7168
        if ($is_platform_admin) {
7169
            if ($user_is_global_admin) {
7170
                return false;
7171
            } else {
7172
                return true;
7173
            }
7174
        } else {
7175
            return false;
7176
        }
7177
    }
7178
}
7179
7180
/**
7181
 * @param int  $admin_id_to_check
7182
 * @param int  $my_user_id
7183
 * @param bool $allow_session_admin
7184
 *
7185
 * @return bool|null
7186
 */
7187
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
7188
{
7189
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
7190
        return true;
7191
    } else {
7192
        api_not_allowed();
7193
    }
7194
}
7195
7196
/**
7197
 * Function used to protect a global admin script.
7198
 * The function blocks access when the user has no global platform admin rights.
7199
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
7200
 *
7201
 * @author Julio Montoya
7202
 */
7203
function api_protect_global_admin_script()
7204
{
7205
    if (!api_is_global_platform_admin()) {
7206
        api_not_allowed();
7207
7208
        return false;
7209
    }
7210
7211
    return true;
7212
}
7213
7214
/**
7215
 * Get active template.
7216
 *
7217
 * @param string    theme type (optional: default)
7218
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
7219
 *
7220
 * @return string actived template path
7221
 */
7222
function api_get_template($path_type = 'rel')
7223
{
7224
    $path_types = ['rel', 'abs'];
7225
    $template_path = '';
7226
    if (in_array($path_type, $path_types)) {
7227
        if ($path_type == 'rel') {
7228
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
7229
        } else {
7230
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
7231
        }
7232
    }
7233
    $actived_theme = 'default';
7234
    if (api_get_setting('active_template')) {
7235
        $actived_theme = api_get_setting('active_template');
7236
    }
7237
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
7238
7239
    return $actived_theme_path;
7240
}
7241
7242
/**
7243
 * Check browser support for specific file types or features
7244
 * This function checks if the user's browser supports a file format or given
7245
 * feature, or returns the current browser and major version when
7246
 * $format=check_browser. Only a limited number of formats and features are
7247
 * checked by this method. Make sure you check its definition first.
7248
 *
7249
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
7250
 *
7251
 * @return bool or return text array if $format=check_browser
7252
 *
7253
 * @author Juan Carlos Raña Trabado
7254
 */
7255
function api_browser_support($format = '')
7256
{
7257
    $browser = new Browser();
7258
    $current_browser = $browser->getBrowser();
7259
    $a_versiontemp = explode('.', $browser->getVersion());
7260
    $current_majorver = $a_versiontemp[0];
7261
7262
    static $result;
7263
7264
    if (isset($result[$format])) {
7265
        return $result[$format];
7266
    }
7267
7268
    // Native svg support
7269
    if ($format == 'svg') {
7270
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7271
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
7272
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
7273
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
7274
            ($current_browser == 'Opera' && $current_majorver >= 9)
7275
        ) {
7276
            $result[$format] = true;
7277
7278
            return true;
7279
        } else {
7280
            $result[$format] = false;
7281
7282
            return false;
7283
        }
7284
    } elseif ($format == 'pdf') {
7285
        // native pdf support
7286
        if (($current_browser == 'Chrome' && $current_majorver >= 6) ||
7287
            ('Firefox' === $current_browser && $current_majorver >= 15)
7288
        ) {
7289
            $result[$format] = true;
7290
7291
            return true;
7292
        } else {
7293
            $result[$format] = false;
7294
7295
            return false;
7296
        }
7297
    } elseif ($format == 'tif' || $format == 'tiff') {
7298
        //native tif support
7299
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7300
            $result[$format] = true;
7301
7302
            return true;
7303
        } else {
7304
            $result[$format] = false;
7305
7306
            return false;
7307
        }
7308
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
7309
        //native ogg, ogv,oga support
7310
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
7311
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
7312
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
7313
            $result[$format] = true;
7314
7315
            return true;
7316
        } else {
7317
            $result[$format] = false;
7318
7319
            return false;
7320
        }
7321
    } elseif ($format == 'mpg' || $format == 'mpeg') {
7322
        //native mpg support
7323
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
7324
            $result[$format] = true;
7325
7326
            return true;
7327
        } else {
7328
            $result[$format] = false;
7329
7330
            return false;
7331
        }
7332
    } elseif ($format == 'mp4') {
7333
        //native mp4 support (TODO: Android, iPhone)
7334
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
7335
            $result[$format] = true;
7336
7337
            return true;
7338
        } else {
7339
            $result[$format] = false;
7340
7341
            return false;
7342
        }
7343
    } elseif ($format == 'mov') {
7344
        //native mov support( TODO:check iPhone)
7345
        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...
7346
            $result[$format] = true;
7347
7348
            return true;
7349
        } else {
7350
            $result[$format] = false;
7351
7352
            return false;
7353
        }
7354
    } elseif ($format == 'avi') {
7355
        //native avi support
7356
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7357
            $result[$format] = true;
7358
7359
            return true;
7360
        } else {
7361
            $result[$format] = false;
7362
7363
            return false;
7364
        }
7365
    } elseif ($format == 'wmv') {
7366
        //native wmv support
7367
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7368
            $result[$format] = true;
7369
7370
            return true;
7371
        } else {
7372
            $result[$format] = false;
7373
7374
            return false;
7375
        }
7376
    } elseif ($format == 'webm') {
7377
        //native webm support (TODO:check IE9, Chrome9, Android)
7378
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
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
        ) {
7384
            $result[$format] = true;
7385
7386
            return true;
7387
        } else {
7388
            $result[$format] = false;
7389
7390
            return false;
7391
        }
7392
    } elseif ($format == 'wav') {
7393
        //native wav support (only some codecs !)
7394
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7395
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
7396
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7397
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7398
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
7399
            $current_browser == 'Android' ||
7400
            $current_browser == 'iPhone'
7401
        ) {
7402
            $result[$format] = true;
7403
7404
            return true;
7405
        } else {
7406
            $result[$format] = false;
7407
7408
            return false;
7409
        }
7410
    } elseif ($format == 'mid' || $format == 'kar') {
7411
        //native midi support (TODO:check Android)
7412
        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...
7413
            $result[$format] = true;
7414
7415
            return true;
7416
        } else {
7417
            $result[$format] = false;
7418
7419
            return false;
7420
        }
7421
    } elseif ($format == 'wma') {
7422
        //native wma support
7423
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7424
            $result[$format] = true;
7425
7426
            return true;
7427
        } else {
7428
            $result[$format] = false;
7429
7430
            return false;
7431
        }
7432
    } elseif ($format == 'au') {
7433
        //native au support
7434
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7435
            $result[$format] = true;
7436
7437
            return true;
7438
        } else {
7439
            $result[$format] = false;
7440
7441
            return false;
7442
        }
7443
    } elseif ($format == 'mp3') {
7444
        //native mp3 support (TODO:check Android, iPhone)
7445
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
7446
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
7447
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7448
            $current_browser == 'Android' ||
7449
            $current_browser == 'iPhone' ||
7450
            $current_browser == 'Firefox'
7451
        ) {
7452
            $result[$format] = true;
7453
7454
            return true;
7455
        } else {
7456
            $result[$format] = false;
7457
7458
            return false;
7459
        }
7460
    } elseif ($format == 'autocapitalize') {
7461
        // Help avoiding showing the autocapitalize option if the browser doesn't
7462
        // support it: this attribute is against the HTML5 standard
7463
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
7464
            return true;
7465
        } else {
7466
            return false;
7467
        }
7468
    } elseif ($format == "check_browser") {
7469
        $array_check_browser = [$current_browser, $current_majorver];
7470
7471
        return $array_check_browser;
7472
    } else {
7473
        $result[$format] = false;
7474
7475
        return false;
7476
    }
7477
}
7478
7479
/**
7480
 * This function checks if exist path and file browscap.ini
7481
 * In order for this to work, your browscap configuration setting in php.ini
7482
 * must point to the correct location of the browscap.ini file on your system
7483
 * http://php.net/manual/en/function.get-browser.php.
7484
 *
7485
 * @return bool
7486
 *
7487
 * @author Juan Carlos Raña Trabado
7488
 */
7489
function api_check_browscap()
7490
{
7491
    $setting = ini_get('browscap');
7492
    if ($setting) {
7493
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7494
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7495
            return true;
7496
        }
7497
    }
7498
7499
    return false;
7500
}
7501
7502
/**
7503
 * Returns the <script> HTML tag.
7504
 */
7505
function api_get_js($file)
7506
{
7507
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7508
}
7509
7510
/**
7511
 * Returns the <script> HTML tag.
7512
 *
7513
 * @return string
7514
 */
7515
function api_get_asset($file)
7516
{
7517
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
7518
}
7519
7520
/**
7521
 * Returns the <script> HTML tag.
7522
 *
7523
 * @param string $file
7524
 * @param string $media
7525
 *
7526
 * @return string
7527
 */
7528
function api_get_css_asset($file, $media = 'screen')
7529
{
7530
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7531
}
7532
7533
/**
7534
 * Returns the <link> HTML tag.
7535
 *
7536
 * @param string $file
7537
 * @param string $media
7538
 */
7539
function api_get_css($file, $media = 'screen')
7540
{
7541
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7542
}
7543
7544
/**
7545
 * Returns the js header to include the jquery library.
7546
 */
7547
function api_get_jquery_js()
7548
{
7549
    return api_get_asset('jquery/dist/jquery.min.js');
7550
}
7551
7552
/**
7553
 * Returns the jquery path.
7554
 *
7555
 * @return string
7556
 */
7557
function api_get_jquery_web_path()
7558
{
7559
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
7560
}
7561
7562
/**
7563
 * @return string
7564
 */
7565
function api_get_jquery_ui_js_web_path()
7566
{
7567
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7568
}
7569
7570
/**
7571
 * @return string
7572
 */
7573
function api_get_jquery_ui_css_web_path()
7574
{
7575
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7576
}
7577
7578
/**
7579
 * Returns the jquery-ui library js headers.
7580
 *
7581
 * @param   bool    add the jqgrid library
7582
 *
7583
 * @return string html tags
7584
 */
7585
function api_get_jquery_ui_js($include_jqgrid = false)
7586
{
7587
    $libraries = [];
7588
    if ($include_jqgrid) {
7589
        $libraries[] = 'jqgrid';
7590
    }
7591
7592
    return api_get_jquery_libraries_js($libraries);
7593
}
7594
7595
function api_get_jqgrid_js()
7596
{
7597
    return api_get_jquery_libraries_js(['jqgrid']);
7598
}
7599
7600
/**
7601
 * Returns the jquery library js and css headers.
7602
 *
7603
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
7604
 * @param   bool    add the jquery library
7605
 *
7606
 * @return string html tags
7607
 */
7608
function api_get_jquery_libraries_js($libraries)
7609
{
7610
    $js = '';
7611
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
7612
7613
    //jqgrid js and css
7614
    if (in_array('jqgrid', $libraries)) {
7615
        $languaje = 'en';
7616
        $platform_isocode = strtolower(api_get_language_isocode());
7617
7618
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7619
        $jqgrid_langs = [
7620
            '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',
7621
        ];
7622
7623
        if (in_array($platform_isocode, $jqgrid_langs)) {
7624
            $languaje = $platform_isocode;
7625
        }
7626
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
7627
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
7628
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
7629
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
7630
    }
7631
7632
    //Document multiple upload funcionality
7633
    if (in_array('jquery-upload', $libraries)) {
7634
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7635
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7636
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7637
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7638
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7639
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7640
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7641
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7642
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7643
7644
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7645
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7646
    }
7647
7648
    // jquery datepicker
7649
    if (in_array('datepicker', $libraries)) {
7650
        $languaje = 'en-GB';
7651
        $platform_isocode = strtolower(api_get_language_isocode());
7652
7653
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7654
        $datapicker_langs = [
7655
            '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',
7656
        ];
7657
        if (in_array($platform_isocode, $datapicker_langs)) {
7658
            $languaje = $platform_isocode;
7659
        }
7660
7661
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7662
        $script = '<script>
7663
        $(function(){
7664
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7665
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7666
        });
7667
        </script>
7668
        ';
7669
        $js .= $script;
7670
    }
7671
7672
    return $js;
7673
}
7674
7675
/**
7676
 * Returns the URL to the course or session, removing the complexity of the URL
7677
 * building piece by piece.
7678
 *
7679
 * This function relies on api_get_course_info()
7680
 *
7681
 * @param string $courseCode The course code - optional (takes it from context if not given)
7682
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7683
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7684
 *
7685
 * @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
7686
 *
7687
 * @author  Julio Montoya <[email protected]>
7688
 */
7689
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7690
{
7691
    $courseDirectory = '';
7692
    $url = '';
7693
    // If courseCode not set, get context or []
7694
    if (empty($courseCode)) {
7695
        $courseInfo = api_get_course_info();
7696
    } else {
7697
        $courseInfo = api_get_course_info($courseCode);
7698
    }
7699
7700
    // If course defined, get directory, otherwise keep empty string
7701
    if (!empty($courseInfo['directory'])) {
7702
        $courseDirectory = $courseInfo['directory'];
7703
    }
7704
7705
    // If sessionId not set, get context or 0
7706
    if (empty($sessionId)) {
7707
        $sessionId = api_get_session_id();
7708
    }
7709
7710
    // If groupId not set, get context or 0
7711
    if (empty($groupId)) {
7712
        $groupId = api_get_group_id();
7713
    }
7714
7715
    // Build the URL
7716
    if (!empty($courseDirectory)) {
7717
        // directory not empty, so we do have a course
7718
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7719
    } elseif (!empty($sessionId) && api_get_configuration_value('remove_session_url') !== true) {
7720
        // if the course was unset and the session was set, send directly to the session
7721
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7722
    }
7723
    // if not valid combination was found, return an empty string
7724
    return $url;
7725
}
7726
7727
/**
7728
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7729
 *
7730
 * @return bool true if multi site is enabled
7731
 */
7732
function api_get_multiple_access_url()
7733
{
7734
    global $_configuration;
7735
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7736
        return true;
7737
    }
7738
7739
    return false;
7740
}
7741
7742
/**
7743
 * Just a synonym for api_get_multiple_access_url().
7744
 *
7745
 * @return bool
7746
 */
7747
function api_is_multiple_url_enabled()
7748
{
7749
    return api_get_multiple_access_url();
7750
}
7751
7752
/**
7753
 * Returns a md5 unique id.
7754
 *
7755
 * @todo add more parameters
7756
 */
7757
function api_get_unique_id()
7758
{
7759
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7760
7761
    return $id;
7762
}
7763
7764
/**
7765
 * Get home path.
7766
 *
7767
 * @return string
7768
 */
7769
function api_get_home_path()
7770
{
7771
    // FIX : Start the routing determination from central path definition
7772
    $home = api_get_path(SYS_HOME_PATH);
7773
    if (api_get_multiple_access_url()) {
7774
        $access_url_id = api_get_current_access_url_id();
7775
        $url_info = api_get_access_url($access_url_id);
7776
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
7777
        $clean_url = api_replace_dangerous_char($url);
7778
        $clean_url = str_replace('/', '-', $clean_url);
7779
        $clean_url .= '/';
7780
        if ($clean_url != 'localhost/') {
7781
            // means that the multiple URL was not well configured we don't rename the $home variable
7782
            return "{$home}{$clean_url}";
7783
        }
7784
    }
7785
7786
    return $home;
7787
}
7788
7789
/**
7790
 * @param int Course id
7791
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7792
 * @param int the item id (tool id, exercise id, lp id)
7793
 *
7794
 * @return bool
7795
 */
7796
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7797
{
7798
    if (api_is_platform_admin()) {
7799
        return false;
7800
    }
7801
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
7802
        if (empty($course_code)) {
7803
            $course_code = api_get_course_id();
7804
        }
7805
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7806
        $item_id = intval($item_id);
7807
        $link_type = intval($link_type);
7808
        $course_code = Database::escape_string($course_code);
7809
        $sql = "SELECT locked FROM $table
7810
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7811
        $result = Database::query($sql);
7812
        if (Database::num_rows($result)) {
7813
            return true;
7814
        }
7815
    }
7816
7817
    return false;
7818
}
7819
7820
/**
7821
 * Blocks a page if the item was added in a gradebook.
7822
 *
7823
 * @param int       exercise id, work id, thread id,
7824
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7825
 * see gradebook/lib/be/linkfactory
7826
 * @param string    course code
7827
 *
7828
 * @return false|null
7829
 */
7830
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7831
{
7832
    if (api_is_platform_admin()) {
7833
        return false;
7834
    }
7835
7836
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7837
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
7838
        api_not_allowed(true, $message);
7839
    }
7840
}
7841
7842
/**
7843
 * Checks the PHP version installed is enough to run Chamilo.
7844
 *
7845
 * @param string Include path (used to load the error page)
7846
 */
7847
function api_check_php_version($my_inc_path = null)
7848
{
7849
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
7850
        $global_error_code = 1;
7851
        // Incorrect PHP version
7852
        $global_page = $my_inc_path.'global_error_message.inc.php';
7853
        if (file_exists($global_page)) {
7854
            require $global_page;
7855
        }
7856
        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...
7857
    }
7858
}
7859
7860
/**
7861
 * Checks whether the Archive directory is present and writeable. If not,
7862
 * prints a warning message.
7863
 */
7864
function api_check_archive_dir()
7865
{
7866
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7867
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
7868
        api_not_allowed(true, $message);
7869
    }
7870
}
7871
7872
/**
7873
 * Returns an array of global configuration settings which should be ignored
7874
 * when printing the configuration settings screens.
7875
 *
7876
 * @return array Array of strings, each identifying one of the excluded settings
7877
 */
7878
function api_get_locked_settings()
7879
{
7880
    return [
7881
        'server_type',
7882
        'permanently_remove_deleted_files',
7883
        'account_valid_duration',
7884
        'service_ppt2lp',
7885
        'wcag_anysurfer_public_pages',
7886
        'upload_extensions_list_type',
7887
        'upload_extensions_blacklist',
7888
        'upload_extensions_whitelist',
7889
        'upload_extensions_skip',
7890
        'upload_extensions_replace_by',
7891
        'hide_dltt_markup',
7892
        'split_users_upload_directory',
7893
        'permissions_for_new_directories',
7894
        'permissions_for_new_files',
7895
        'platform_charset',
7896
        'ldap_description',
7897
        'cas_activate',
7898
        'cas_server',
7899
        'cas_server_uri',
7900
        'cas_port',
7901
        'cas_protocol',
7902
        'cas_add_user_activate',
7903
        'update_user_info_cas_with_ldap',
7904
        'languagePriority1',
7905
        'languagePriority2',
7906
        'languagePriority3',
7907
        'languagePriority4',
7908
        'login_is_email',
7909
        'chamilo_database_version',
7910
    ];
7911
}
7912
7913
/**
7914
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7915
 * false if he isn't. If the user ID is given and is an integer, then the same
7916
 * ID is simply returned.
7917
 *
7918
 * @param  int User ID
7919
 *
7920
 * @return bool Integer User ID is logged in, or false otherwise
7921
 */
7922
function api_user_is_login($user_id = null)
7923
{
7924
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
7925
7926
    return $user_id && !api_is_anonymous();
7927
}
7928
7929
/**
7930
 * Guess the real ip for register in the database, even in reverse proxy cases.
7931
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7932
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7933
 * Note: the result of this function is not SQL-safe. Please escape it before
7934
 * inserting in a database.
7935
 *
7936
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7937
 *
7938
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7939
 *
7940
 * @version CEV CHANGE 24APR2012
7941
 */
7942
function api_get_real_ip()
7943
{
7944
    $ip = trim($_SERVER['REMOTE_ADDR']);
7945
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7946
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7947
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7948
        } else {
7949
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7950
        }
7951
        $ip = trim($ip1);
7952
    }
7953
7954
    return $ip;
7955
}
7956
7957
/**
7958
 * Checks whether an IP is included inside an IP range.
7959
 *
7960
 * @param string IP address
7961
 * @param string IP range
7962
 * @param string $ip
7963
 *
7964
 * @return bool True if IP is in the range, false otherwise
7965
 *
7966
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7967
 * @author Yannick Warnier for improvements and managment of multiple ranges
7968
 *
7969
 * @todo check for IPv6 support
7970
 */
7971
function api_check_ip_in_range($ip, $range)
7972
{
7973
    if (empty($ip) or empty($range)) {
7974
        return false;
7975
    }
7976
    $ip_ip = ip2long($ip);
7977
    // divide range param into array of elements
7978
    if (strpos($range, ',') !== false) {
7979
        $ranges = explode(',', $range);
7980
    } else {
7981
        $ranges = [$range];
7982
    }
7983
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7984
        $range = trim($range);
7985
        if (empty($range)) {
7986
            continue;
7987
        }
7988
        if (strpos($range, '/') === false) {
7989
            if (strcmp($ip, $range) === 0) {
7990
                return true; // there is a direct IP match, return OK
7991
            }
7992
            continue; //otherwise, get to the next range
7993
        }
7994
        // the range contains a "/", so analyse completely
7995
        list($net, $mask) = explode("/", $range);
7996
7997
        $ip_net = ip2long($net);
7998
        // mask binary magic
7999
        $ip_mask = ~((1 << (32 - $mask)) - 1);
8000
8001
        $ip_ip_net = $ip_ip & $ip_mask;
8002
        if ($ip_ip_net == $ip_net) {
8003
            return true;
8004
        }
8005
    }
8006
8007
    return false;
8008
}
8009
8010
function api_check_user_access_to_legal($courseInfo)
8011
{
8012
    if (empty($courseInfo)) {
8013
        return false;
8014
    }
8015
8016
    $visibility = (int) $courseInfo['visibility'];
8017
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
8018
8019
    return
8020
        in_array($visibility, $visibilityList) ||
8021
        api_is_drh() ||
8022
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
8023
}
8024
8025
/**
8026
 * Checks if the global chat is enabled or not.
8027
 *
8028
 * @return bool
8029
 */
8030
function api_is_global_chat_enabled()
8031
{
8032
    return
8033
        !api_is_anonymous() &&
8034
        api_get_setting('allow_global_chat') === 'true' &&
8035
        api_get_setting('allow_social_tool') === 'true';
8036
}
8037
8038
/**
8039
 * @todo Fix tool_visible_by_default_at_creation labels
8040
 *
8041
 * @param int   $item_id
8042
 * @param int   $tool_id
8043
 * @param int   $group_id   id
8044
 * @param array $courseInfo
8045
 * @param int   $sessionId
8046
 * @param int   $userId
8047
 */
8048
function api_set_default_visibility(
8049
    $item_id,
8050
    $tool_id,
8051
    $group_id = 0,
8052
    $courseInfo = [],
8053
    $sessionId = 0,
8054
    $userId = 0
8055
) {
8056
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
8057
    $courseId = $courseInfo['real_id'];
8058
    $courseCode = $courseInfo['code'];
8059
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
8060
    $userId = empty($userId) ? api_get_user_id() : $userId;
8061
8062
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
8063
    if (is_null($group_id)) {
8064
        $group_id = 0;
8065
    } else {
8066
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
8067
    }
8068
8069
    $groupInfo = [];
8070
    if (!empty($group_id)) {
8071
        $groupInfo = GroupManager::get_group_properties($group_id);
8072
    }
8073
    $original_tool_id = $tool_id;
8074
8075
    switch ($tool_id) {
8076
        case TOOL_LINK:
8077
        case TOOL_LINK_CATEGORY:
8078
            $tool_id = 'links';
8079
            break;
8080
        case TOOL_DOCUMENT:
8081
            $tool_id = 'documents';
8082
            break;
8083
        case TOOL_LEARNPATH:
8084
            $tool_id = 'learning';
8085
            break;
8086
        case TOOL_ANNOUNCEMENT:
8087
            $tool_id = 'announcements';
8088
            break;
8089
        case TOOL_FORUM:
8090
        case TOOL_FORUM_CATEGORY:
8091
        case TOOL_FORUM_THREAD:
8092
            $tool_id = 'forums';
8093
            break;
8094
        case TOOL_QUIZ:
8095
            $tool_id = 'quiz';
8096
            break;
8097
    }
8098
    $setting = api_get_setting('tool_visible_by_default_at_creation');
8099
8100
    if (isset($setting[$tool_id])) {
8101
        $visibility = 'invisible';
8102
        if ($setting[$tool_id] == 'true') {
8103
            $visibility = 'visible';
8104
        }
8105
8106
        // Read the portal and course default visibility
8107
        if ($tool_id === 'documents') {
8108
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
8109
        }
8110
8111
        api_item_property_update(
8112
            $courseInfo,
8113
            $original_tool_id,
8114
            $item_id,
8115
            $visibility,
8116
            $userId,
8117
            $groupInfo,
8118
            null,
8119
            null,
8120
            null,
8121
            $sessionId
8122
        );
8123
8124
        // Fixes default visibility for tests
8125
        switch ($original_tool_id) {
8126
            case TOOL_QUIZ:
8127
                if (empty($sessionId)) {
8128
                    $objExerciseTmp = new Exercise($courseId);
8129
                    $objExerciseTmp->read($item_id);
8130
                    if ($visibility == 'visible') {
8131
                        $objExerciseTmp->enable();
8132
                        $objExerciseTmp->save();
8133
                    } else {
8134
                        $objExerciseTmp->disable();
8135
                        $objExerciseTmp->save();
8136
                    }
8137
                }
8138
                break;
8139
        }
8140
    }
8141
}
8142
8143
/**
8144
 * @return string
8145
 */
8146
function api_get_security_key()
8147
{
8148
    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...
8149
}
8150
8151
/**
8152
 * @param int $user_id
8153
 * @param int $courseId
8154
 * @param int $session_id
8155
 *
8156
 * @return array
8157
 */
8158
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
8159
{
8160
    $user_roles = [];
8161
    $courseInfo = api_get_course_info_by_id($courseId);
8162
    $course_code = $courseInfo['code'];
8163
8164
    $url_id = api_get_current_access_url_id();
8165
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
8166
        $user_roles[] = PLATFORM_ADMIN;
8167
    }
8168
8169
    /*if (api_is_drh()) {
8170
        $user_roles[] = DRH;
8171
    }*/
8172
8173
    if (!empty($session_id)) {
8174
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
8175
            $user_roles[] = SESSION_GENERAL_COACH;
8176
        }
8177
    }
8178
8179
    if (!empty($course_code)) {
8180
        if (empty($session_id)) {
8181
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
8182
                $user_roles[] = COURSEMANAGER;
8183
            }
8184
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
8185
                $user_roles[] = COURSE_TUTOR;
8186
            }
8187
8188
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
8189
                $user_roles[] = COURSE_STUDENT;
8190
            }
8191
        } else {
8192
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
8193
                $user_id,
8194
                $courseId,
8195
                $session_id
8196
            );
8197
8198
            if (!empty($user_status_in_session)) {
8199
                if ($user_status_in_session == 0) {
8200
                    $user_roles[] = SESSION_STUDENT;
8201
                }
8202
                if ($user_status_in_session == 2) {
8203
                    $user_roles[] = SESSION_COURSE_COACH;
8204
                }
8205
            }
8206
8207
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
8208
               $user_roles[] = SESSION_COURSE_COACH;
8209
            }*/
8210
        }
8211
    }
8212
8213
    return $user_roles;
8214
}
8215
8216
/**
8217
 * @param int $courseId
8218
 * @param int $session_id
8219
 *
8220
 * @return bool
8221
 */
8222
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
8223
{
8224
    if (api_is_platform_admin()) {
8225
        return true;
8226
    }
8227
8228
    $user_id = api_get_user_id();
8229
8230
    if (empty($courseId)) {
8231
        $courseId = api_get_course_int_id();
8232
    }
8233
8234
    if (empty($session_id)) {
8235
        $session_id = api_get_session_id();
8236
    }
8237
8238
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
8239
8240
    if (in_array(SESSION_COURSE_COACH, $roles)) {
8241
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
8242
        return true;
8243
    } else {
8244
        if (in_array(COURSEMANAGER, $roles)) {
8245
            return true;
8246
        }
8247
8248
        return false;
8249
    }
8250
}
8251
8252
/**
8253
 * @param string $file
8254
 *
8255
 * @return string
8256
 */
8257
function api_get_js_simple($file)
8258
{
8259
    return '<script src="'.$file.'"></script>'."\n";
8260
}
8261
8262
function api_set_settings_and_plugins()
8263
{
8264
    global $_configuration;
8265
    $_setting = [];
8266
    $_plugins = [];
8267
8268
    // access_url == 1 is the default chamilo location
8269
    $settings_by_access_list = [];
8270
    $access_url_id = api_get_current_access_url_id();
8271
    if ($access_url_id != 1) {
8272
        $url_info = api_get_access_url($_configuration['access_url']);
8273
        if ($url_info['active'] == 1) {
8274
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
8275
            foreach ($settings_by_access as &$row) {
8276
                if (empty($row['variable'])) {
8277
                    $row['variable'] = 0;
8278
                }
8279
                if (empty($row['subkey'])) {
8280
                    $row['subkey'] = 0;
8281
                }
8282
                if (empty($row['category'])) {
8283
                    $row['category'] = 0;
8284
                }
8285
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
8286
            }
8287
        }
8288
    }
8289
8290
    $result = api_get_settings(null, 'list', 1);
8291
8292
    foreach ($result as &$row) {
8293
        if ($access_url_id != 1) {
8294
            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...
8295
                $var = empty($row['variable']) ? 0 : $row['variable'];
8296
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
8297
                $category = empty($row['category']) ? 0 : $row['category'];
8298
            }
8299
8300
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
8301
                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...
8302
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
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...
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...
8303
                    if ($row['subkey'] == null) {
8304
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8305
                    } else {
8306
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8307
                    }
8308
                } else {
8309
                    if ($row['subkey'] == null) {
8310
                        $_setting[$row['variable']] = $row['selected_value'];
8311
                    } else {
8312
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8313
                    }
8314
                }
8315
            } else {
8316
                if ($row['subkey'] == null) {
8317
                    $_setting[$row['variable']] = $row['selected_value'];
8318
                } else {
8319
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8320
                }
8321
            }
8322
        } else {
8323
            if ($row['subkey'] == null) {
8324
                $_setting[$row['variable']] = $row['selected_value'];
8325
            } else {
8326
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8327
            }
8328
        }
8329
    }
8330
8331
    $result = api_get_settings('Plugins', 'list', $access_url_id);
8332
    $_plugins = [];
8333
    foreach ($result as &$row) {
8334
        $key = &$row['variable'];
8335
        if (is_string($_setting[$key])) {
8336
            $_setting[$key] = [];
8337
        }
8338
        $_setting[$key][] = $row['selected_value'];
8339
        $_plugins[$key][] = $row['selected_value'];
8340
    }
8341
8342
    $_SESSION['_setting'] = $_setting;
8343
    $_SESSION['_plugins'] = $_plugins;
8344
}
8345
8346
/**
8347
 * Modify default memory_limit and max_execution_time limits
8348
 * Needed when processing long tasks.
8349
 */
8350
function api_set_more_memory_and_time_limits()
8351
{
8352
    if (function_exists('ini_set')) {
8353
        api_set_memory_limit('2048M');
8354
        ini_set('max_execution_time', 3600);
8355
    }
8356
}
8357
8358
/**
8359
 * Tries to set memory limit, if authorized and new limit is higher than current.
8360
 *
8361
 * @param string $mem New memory limit
8362
 *
8363
 * @return bool True on success, false on failure or current is higher than suggested
8364
 * @assert (null) === false
8365
 * @assert (-1) === false
8366
 * @assert (0) === true
8367
 * @assert ('1G') === true
8368
 */
8369
function api_set_memory_limit($mem)
8370
{
8371
    //if ini_set() not available, this function is useless
8372
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
8373
        return false;
8374
    }
8375
8376
    $memory_limit = ini_get('memory_limit');
8377
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8378
        ini_set('memory_limit', $mem);
8379
8380
        return true;
8381
    }
8382
8383
    return false;
8384
}
8385
8386
/**
8387
 * Gets memory limit in bytes.
8388
 *
8389
 * @param string The memory size (128M, 1G, 1000K, etc)
8390
 *
8391
 * @return int
8392
 * @assert (null) === false
8393
 * @assert ('1t')  === 1099511627776
8394
 * @assert ('1g')  === 1073741824
8395
 * @assert ('1m')  === 1048576
8396
 * @assert ('100k') === 102400
8397
 */
8398
function api_get_bytes_memory_limit($mem)
8399
{
8400
    $size = strtolower(substr($mem, -1));
8401
8402
    switch ($size) {
8403
        case 't':
8404
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8405
            break;
8406
        case 'g':
8407
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8408
            break;
8409
        case 'm':
8410
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8411
            break;
8412
        case 'k':
8413
            $mem = intval(substr($mem, 0, -1)) * 1024;
8414
            break;
8415
        default:
8416
            // we assume it's integer only
8417
            $mem = intval($mem);
8418
            break;
8419
    }
8420
8421
    return $mem;
8422
}
8423
8424
/**
8425
 * Finds all the information about a user from username instead of user id.
8426
 *
8427
 * @param string $officialCode
8428
 *
8429
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8430
 *
8431
 * @author Yannick Warnier <[email protected]>
8432
 */
8433
function api_get_user_info_from_official_code($officialCode)
8434
{
8435
    if (empty($officialCode)) {
8436
        return false;
8437
    }
8438
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8439
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8440
    $result = Database::query($sql);
8441
    if (Database::num_rows($result) > 0) {
8442
        $result_array = Database::fetch_array($result);
8443
8444
        return _api_format_user($result_array);
8445
    }
8446
8447
    return false;
8448
}
8449
8450
/**
8451
 * @param string $usernameInputId
8452
 * @param string $passwordInputId
8453
 *
8454
 * @return string|null
8455
 */
8456
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8457
{
8458
    $checkPass = api_get_setting('allow_strength_pass_checker');
8459
    $useStrengthPassChecker = $checkPass === 'true';
8460
8461
    if ($useStrengthPassChecker === false) {
8462
        return null;
8463
    }
8464
8465
    $translations = [
8466
        'wordLength' => get_lang('PasswordIsTooShort'),
8467
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
8468
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
8469
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
8470
        'wordRepetitions' => get_lang('TooManyRepetitions'),
8471
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
8472
        'errorList' => get_lang('ErrorsFound'),
8473
        'veryWeak' => get_lang('PasswordVeryWeak'),
8474
        'weak' => get_lang('PasswordWeak'),
8475
        'normal' => get_lang('PasswordNormal'),
8476
        'medium' => get_lang('PasswordMedium'),
8477
        'strong' => get_lang('PasswordStrong'),
8478
        'veryStrong' => get_lang('PasswordVeryStrong'),
8479
    ];
8480
8481
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
8482
    $js .= "<script>
8483
    var errorMessages = {
8484
        password_to_short : \"".get_lang('PasswordIsTooShort')."\",
8485
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
8486
    };
8487
8488
    $(function() {
8489
        var lang = ".json_encode($translations).";
8490
        var options = {
8491
            common: {
8492
                onLoad: function () {
8493
                    //$('#messages').text('Start typing password');
8494
8495
                    var inputGroup = $('".$passwordInputId."').parents('.input-group');
8496
8497
                    if (inputGroup.length > 0) {
8498
                        inputGroup.find('.progress').insertAfter(inputGroup);
8499
                    }
8500
                }
8501
            },
8502
            ui: {
8503
                showVerdictsInsideProgressBar: true
8504
            },
8505
            onKeyUp: function (evt) {
8506
                $(evt.target).pwstrength('outputErrorList');
8507
            },
8508
            errorMessages : errorMessages,
8509
            viewports: {
8510
                progress: '#password_progress',
8511
                verdict: '#password-verdict',
8512
                errors: '#password-errors'
8513
            },
8514
            usernameField: '$usernameInputId'
8515
        };
8516
        options.i18n = {
8517
            t: function (key) {
8518
                var result = lang[key];
8519
                return result === key ? '' : result; // This assumes you return the
8520
            }
8521
        };
8522
        $('".$passwordInputId."').pwstrength(options);
8523
    });
8524
    </script>";
8525
8526
    return $js;
8527
}
8528
8529
/**
8530
 * create an user extra field called 'captcha_blocked_until_date'.
8531
 *
8532
 * @param string $username
8533
 *
8534
 * @return bool
8535
 */
8536
function api_block_account_captcha($username)
8537
{
8538
    $userInfo = api_get_user_info_from_username($username);
8539
    if (empty($userInfo)) {
8540
        return false;
8541
    }
8542
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8543
    $time = time() + $minutesToBlock * 60;
8544
    UserManager::update_extra_field_value(
8545
        $userInfo['user_id'],
8546
        'captcha_blocked_until_date',
8547
        api_get_utc_datetime($time)
8548
    );
8549
8550
    return true;
8551
}
8552
8553
/**
8554
 * @param string $username
8555
 *
8556
 * @return bool
8557
 */
8558
function api_clean_account_captcha($username)
8559
{
8560
    $userInfo = api_get_user_info_from_username($username);
8561
    if (empty($userInfo)) {
8562
        return false;
8563
    }
8564
    Session::erase('loginFailedCount');
8565
    UserManager::update_extra_field_value(
8566
        $userInfo['user_id'],
8567
        'captcha_blocked_until_date',
8568
        null
8569
    );
8570
8571
    return true;
8572
}
8573
8574
/**
8575
 * @param string $username
8576
 *
8577
 * @return bool
8578
 */
8579
function api_get_user_blocked_by_captcha($username)
8580
{
8581
    $userInfo = api_get_user_info_from_username($username);
8582
    if (empty($userInfo)) {
8583
        return false;
8584
    }
8585
    $data = UserManager::get_extra_user_data_by_field(
8586
        $userInfo['user_id'],
8587
        'captcha_blocked_until_date'
8588
    );
8589
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8590
        return $data['captcha_blocked_until_date'];
8591
    }
8592
8593
    return false;
8594
}
8595
8596
/**
8597
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8598
 * Postfix the text with "..." if it has been truncated.
8599
 *
8600
 * @param string $text
8601
 * @param int    $number
8602
 *
8603
 * @return string
8604
 *
8605
 * @author hubert borderiou
8606
 */
8607
function api_get_short_text_from_html($text, $number)
8608
{
8609
    // Delete script and style tags
8610
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8611
    $text = api_html_entity_decode($text);
8612
    $out_res = api_remove_tags_with_space($text, false);
8613
    $postfix = "...";
8614
    if (strlen($out_res) > $number) {
8615
        $out_res = substr($out_res, 0, $number).$postfix;
8616
    }
8617
8618
    return $out_res;
8619
}
8620
8621
/**
8622
 * Replace tags with a space in a text.
8623
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8624
 *
8625
 * @return string
8626
 *
8627
 * @author hubert borderiou
8628
 */
8629
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8630
{
8631
    $out_res = $in_html;
8632
    if ($in_double_quote_replace) {
8633
        $out_res = str_replace('"', "''", $out_res);
8634
    }
8635
    // avoid text stuck together when tags are removed, adding a space after >
8636
    $out_res = str_replace(">", "> ", $out_res);
8637
    $out_res = strip_tags($out_res);
8638
8639
    return $out_res;
8640
}
8641
8642
/**
8643
 * If true, the drh can access all content (courses, users) inside a session.
8644
 *
8645
 * @return bool
8646
 */
8647
function api_drh_can_access_all_session_content()
8648
{
8649
    return api_get_setting('drh_can_access_all_session_content') === 'true';
8650
}
8651
8652
/**
8653
 * @param string $tool
8654
 * @param string $setting
8655
 * @param int    $defaultValue
8656
 *
8657
 * @return string
8658
 */
8659
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8660
{
8661
    global $_configuration;
8662
    if (isset($_configuration[$tool]) &&
8663
        isset($_configuration[$tool]['default_settings']) &&
8664
        isset($_configuration[$tool]['default_settings'][$setting])
8665
    ) {
8666
        return $_configuration[$tool]['default_settings'][$setting];
8667
    }
8668
8669
    return $defaultValue;
8670
}
8671
8672
/**
8673
 * Checks if user can login as another user.
8674
 *
8675
 * @param int $loginAsUserId the user id to log in
8676
 * @param int $userId        my user id
8677
 *
8678
 * @return bool
8679
 */
8680
function api_can_login_as($loginAsUserId, $userId = null)
8681
{
8682
    if (empty($userId)) {
8683
        $userId = api_get_user_id();
8684
    }
8685
    if ($loginAsUserId == $userId) {
8686
        return false;
8687
    }
8688
8689
    if (empty($loginAsUserId)) {
8690
        return false;
8691
    }
8692
8693
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8694
        return false;
8695
    }
8696
8697
    // Check if the user to login is an admin
8698
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8699
        // Only super admins can login to admin accounts
8700
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8701
            return false;
8702
        }
8703
    }
8704
8705
    $userInfo = api_get_user_info($loginAsUserId);
8706
    $isDrh = function () use ($loginAsUserId) {
8707
        if (api_is_drh()) {
8708
            if (api_drh_can_access_all_session_content()) {
8709
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8710
                    'drh_all',
8711
                    api_get_user_id()
8712
                );
8713
                $userList = [];
8714
                if (is_array($users)) {
8715
                    foreach ($users as $user) {
8716
                        $userList[] = $user['user_id'];
8717
                    }
8718
                }
8719
                if (in_array($loginAsUserId, $userList)) {
8720
                    return true;
8721
                }
8722
            } else {
8723
                if (api_is_drh() &&
8724
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8725
                ) {
8726
                    return true;
8727
                }
8728
            }
8729
        }
8730
8731
        return false;
8732
    };
8733
8734
    $loginAsStatusForSessionAdmins = [STUDENT];
8735
8736
    if (api_get_configuration_value('allow_session_admin_login_as_teacher')) {
8737
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8738
    }
8739
8740
    return api_is_platform_admin() ||
8741
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8742
        $isDrh();
8743
}
8744
8745
/**
8746
 * @return bool
8747
 */
8748
function api_is_allowed_in_course()
8749
{
8750
    if (api_is_platform_admin()) {
8751
        return true;
8752
    }
8753
8754
    return Session::read('is_allowed_in_course');
8755
}
8756
8757
function api_set_cookie($name, $value, $expires = 0)
8758
{
8759
    $expires = (int) $expires;
8760
    setcookie($name, $value, $expires, '', '', api_is_https(), true);
8761
}
8762
8763
/**
8764
 * Set the cookie to go directly to the course code $in_firstpage
8765
 * after login.
8766
 *
8767
 * @param string $value is the course code of the course to go
8768
 */
8769
function api_set_firstpage_parameter($value)
8770
{
8771
    api_set_cookie('GotoCourse', $value);
8772
}
8773
8774
/**
8775
 * Delete the cookie to go directly to the course code $in_firstpage
8776
 * after login.
8777
 */
8778
function api_delete_firstpage_parameter()
8779
{
8780
    api_set_cookie('GotoCourse', '', time() - 3600);
8781
}
8782
8783
/**
8784
 * @return bool if course_code for direct course access after login is set
8785
 */
8786
function exist_firstpage_parameter()
8787
{
8788
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8789
}
8790
8791
/**
8792
 * @return string return the course_code of the course where user login
8793
 */
8794
function api_get_firstpage_parameter()
8795
{
8796
    return $_COOKIE['GotoCourse'];
8797
}
8798
8799
/**
8800
 * Return true on https install.
8801
 *
8802
 * @return bool
8803
 */
8804
function api_is_https()
8805
{
8806
    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...
8807
        $_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...
8808
    ) {
8809
        $isSecured = true;
8810
    } else {
8811
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8812
            $isSecured = true;
8813
        } else {
8814
            $isSecured = false;
8815
            // last chance
8816
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8817
                $isSecured = true;
8818
            }
8819
        }
8820
    }
8821
8822
    return $isSecured;
8823
}
8824
8825
/**
8826
 * Return protocol (http or https).
8827
 *
8828
 * @return string
8829
 */
8830
function api_get_protocol()
8831
{
8832
    return api_is_https() ? 'https' : 'http';
8833
}
8834
8835
/**
8836
 * Return a string where " are replaced with 2 '
8837
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8838
 * e.g. : alert("<?php get_lang('Message') ?>");
8839
 * and message contains character ".
8840
 *
8841
 * @param string $in_text
8842
 *
8843
 * @return string
8844
 */
8845
function convert_double_quote_to_single($in_text)
8846
{
8847
    return api_preg_replace('/"/', "''", $in_text);
8848
}
8849
8850
/**
8851
 * Get origin.
8852
 *
8853
 * @param string
8854
 *
8855
 * @return string
8856
 */
8857
function api_get_origin()
8858
{
8859
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
8860
}
8861
8862
/**
8863
 * Warns an user that the portal reach certain limit.
8864
 *
8865
 * @param string $limitName
8866
 */
8867
function api_warn_hosting_contact($limitName)
8868
{
8869
    $hostingParams = api_get_configuration_value(1);
8870
    $email = null;
8871
8872
    if (!empty($hostingParams)) {
8873
        if (isset($hostingParams['hosting_contact_mail'])) {
8874
            $email = $hostingParams['hosting_contact_mail'];
8875
        }
8876
    }
8877
8878
    if (!empty($email)) {
8879
        $subject = get_lang('HostingWarningReached');
8880
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8881
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8882
        if (isset($hostingParams[$limitName])) {
8883
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8884
        }
8885
        api_mail_html(null, $email, $subject, $body);
8886
    }
8887
}
8888
8889
/**
8890
 * Gets value of a variable from app/config/configuration.php
8891
 * Variables that are not set in the configuration.php file but set elsewhere:
8892
 * - virtual_css_theme_folder (vchamilo plugin)
8893
 * - access_url (global.inc.php)
8894
 * - apc/apc_prefix (global.inc.php).
8895
 *
8896
 * @param string $variable
8897
 *
8898
 * @return bool|mixed
8899
 */
8900
function api_get_configuration_value($variable)
8901
{
8902
    global $_configuration;
8903
    // Check the current url id, id = 1 by default
8904
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8905
8906
    $variable = trim($variable);
8907
8908
    // Check if variable exists
8909
    if (isset($_configuration[$variable])) {
8910
        if (is_array($_configuration[$variable])) {
8911
            // Check if it exists for the sub portal
8912
            if (array_key_exists($urlId, $_configuration[$variable])) {
8913
                return $_configuration[$variable][$urlId];
8914
            } else {
8915
                // Try to found element with id = 1 (master portal)
8916
                if (array_key_exists(1, $_configuration[$variable])) {
8917
                    return $_configuration[$variable][1];
8918
                }
8919
            }
8920
        }
8921
8922
        return $_configuration[$variable];
8923
    }
8924
8925
    return false;
8926
}
8927
8928
/**
8929
 * Retreives and returns a value in a hierarchical configuration array
8930
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
8931
 *
8932
 * @param string $path      the successive array keys, separated by the separator
8933
 * @param mixed  $default   value to be returned if not found, null by default
8934
 * @param string $separator '/' by default
8935
 * @param array  $array     the active configuration array by default
8936
 *
8937
 * @return mixed the found value or $default
8938
 */
8939
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
8940
{
8941
    $pos = strpos($path, $separator);
8942
    if (false === $pos) {
8943
        if (is_null($array)) {
8944
            return api_get_configuration_value($path);
8945
        }
8946
        if (is_array($array) && array_key_exists($path, $array)) {
8947
            return $array[$path];
8948
        }
8949
8950
        return $default;
8951
    }
8952
    $key = substr($path, 0, $pos);
8953
    if (is_null($array)) {
8954
        $newArray = api_get_configuration_value($key);
8955
    } elseif (is_array($array) && array_key_exists($key, $array)) {
8956
        $newArray = $array[$key];
8957
    } else {
8958
        return $default;
8959
    }
8960
    if (is_array($newArray)) {
8961
        $newPath = substr($path, $pos + 1);
8962
8963
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
8964
    }
8965
8966
    return $default;
8967
}
8968
8969
/**
8970
 * Retrieves and returns a value in a hierarchical configuration array
8971
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
8972
 *
8973
 * @param array  $array     the recursive array that contains the value to be returned (or not)
8974
 * @param string $path      the successive array keys, separated by the separator
8975
 * @param mixed  $default   the value to be returned if not found
8976
 * @param string $separator the separator substring
8977
 *
8978
 * @return mixed the found value or $default
8979
 */
8980
function api_array_sub_value($array, $path, $default = null, $separator = '/')
8981
{
8982
    $pos = strpos($path, $separator);
8983
    if (false === $pos) {
8984
        if (is_array($array) && array_key_exists($path, $array)) {
8985
            return $array[$path];
8986
        }
8987
8988
        return $default;
8989
    }
8990
    $key = substr($path, 0, $pos);
8991
    if (is_array($array) && array_key_exists($key, $array)) {
8992
        $newArray = $array[$key];
8993
    } else {
8994
        return $default;
8995
    }
8996
    if (is_array($newArray)) {
8997
        $newPath = substr($path, $pos + 1);
8998
8999
        return api_array_sub_value($newArray, $newPath, $default);
9000
    }
9001
9002
    return $default;
9003
}
9004
9005
/**
9006
 * Returns supported image extensions in the portal.
9007
 *
9008
 * @param bool $supportVectors Whether vector images should also be accepted or not
9009
 *
9010
 * @return array Supported image extensions in the portal
9011
 */
9012
function api_get_supported_image_extensions($supportVectors = true)
9013
{
9014
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
9015
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
9016
    if ($supportVectors) {
9017
        array_push($supportedImageExtensions, 'svg');
9018
    }
9019
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
9020
        array_push($supportedImageExtensions, 'webp');
9021
    }
9022
9023
    return $supportedImageExtensions;
9024
}
9025
9026
/**
9027
 * This setting changes the registration status for the campus.
9028
 *
9029
 * @author Patrick Cool <[email protected]>, Ghent University
9030
 *
9031
 * @version August 2006
9032
 *
9033
 * @param bool $listCampus Whether we authorize
9034
 *
9035
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
9036
 */
9037
function api_register_campus($listCampus = true)
9038
{
9039
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
9040
9041
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
9042
    Database::query($sql);
9043
9044
    if (!$listCampus) {
9045
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
9046
        Database::query($sql);
9047
    }
9048
}
9049
9050
/**
9051
 * Checks whether current user is a student boss.
9052
 *
9053
 * @global array $_user
9054
 *
9055
 * @return bool
9056
 */
9057
function api_is_student_boss()
9058
{
9059
    $_user = api_get_user_info();
9060
9061
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
9062
}
9063
9064
/**
9065
 * Check whether the user type should be exclude.
9066
 * Such as invited or anonymous users.
9067
 *
9068
 * @param bool $checkDB Optional. Whether check the user status
9069
 * @param int  $userId  Options. The user id
9070
 *
9071
 * @return bool
9072
 */
9073
function api_is_excluded_user_type($checkDB = false, $userId = 0)
9074
{
9075
    if ($checkDB) {
9076
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
9077
9078
        if ($userId == 0) {
9079
            return true;
9080
        }
9081
9082
        $userInfo = api_get_user_info($userId);
9083
9084
        switch ($userInfo['status']) {
9085
            case INVITEE:
9086
            case ANONYMOUS:
9087
                return true;
9088
            default:
9089
                return false;
9090
        }
9091
    }
9092
9093
    $isInvited = api_is_invitee();
9094
    $isAnonymous = api_is_anonymous();
9095
9096
    if ($isInvited || $isAnonymous) {
9097
        return true;
9098
    }
9099
9100
    return false;
9101
}
9102
9103
/**
9104
 * Get the user status to ignore in reports.
9105
 *
9106
 * @param string $format Optional. The result type (array or string)
9107
 *
9108
 * @return array|string
9109
 */
9110
function api_get_users_status_ignored_in_reports($format = 'array')
9111
{
9112
    $excludedTypes = [
9113
        INVITEE,
9114
        ANONYMOUS,
9115
    ];
9116
9117
    if ($format == 'string') {
9118
        return implode(', ', $excludedTypes);
9119
    }
9120
9121
    return $excludedTypes;
9122
}
9123
9124
/**
9125
 * Set the Site Use Cookie Warning for 1 year.
9126
 */
9127
function api_set_site_use_cookie_warning_cookie()
9128
{
9129
    api_set_cookie('ChamiloUsesCookies', 'ok', time() + 31556926);
9130
}
9131
9132
/**
9133
 * Return true if the Site Use Cookie Warning Cookie warning exists.
9134
 *
9135
 * @return bool
9136
 */
9137
function api_site_use_cookie_warning_cookie_exist()
9138
{
9139
    return isset($_COOKIE['ChamiloUsesCookies']);
9140
}
9141
9142
/**
9143
 * Given a number of seconds, format the time to show hours, minutes and seconds.
9144
 *
9145
 * @param int    $time         The time in seconds
9146
 * @param string $originFormat Optional. PHP o JS
9147
 *
9148
 * @return string (00h00'00")
9149
 */
9150
function api_format_time($time, $originFormat = 'php')
9151
{
9152
    $h = get_lang('h');
9153
    $hours = $time / 3600;
9154
    $mins = ($time % 3600) / 60;
9155
    $secs = ($time % 60);
9156
9157
    if ($time < 0) {
9158
        $hours = 0;
9159
        $mins = 0;
9160
        $secs = 0;
9161
    }
9162
9163
    if ($originFormat == 'js') {
9164
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
9165
    } else {
9166
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
9167
    }
9168
9169
    return $formattedTime;
9170
}
9171
9172
/**
9173
 * Create a new empty directory with index.html file.
9174
 *
9175
 * @param string $name            The new directory name
9176
 * @param string $parentDirectory Directory parent directory name
9177
 *
9178
 * @return bool Return true if the directory was create. Otherwise return false
9179
 */
9180
function api_create_protected_dir($name, $parentDirectory)
9181
{
9182
    $isCreated = false;
9183
9184
    if (!is_writable($parentDirectory)) {
9185
        return false;
9186
    }
9187
9188
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
9189
9190
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
9191
        $fp = fopen($fullPath.'/index.html', 'w');
9192
9193
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource, thus it always evaluated to false.
Loading history...
9194
            if (fwrite($fp, '<html><head><title></title></head><body></body></html>')) {
9195
                $isCreated = true;
9196
            }
9197
        }
9198
9199
        fclose($fp);
9200
    }
9201
9202
    return $isCreated;
9203
}
9204
9205
/**
9206
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
9207
 * Sender name and email can be specified, if not specified
9208
 * name and email of the platform admin are used.
9209
 *
9210
 * @author Bert Vanderkimpen ICT&O UGent
9211
 * @author Yannick Warnier <[email protected]>
9212
 *
9213
 * @param string    name of recipient
9214
 * @param string    email of recipient
9215
 * @param string    email subject
9216
 * @param string    email body
9217
 * @param string    sender name
9218
 * @param string    sender e-mail
9219
 * @param array  $extra_headers        in form $headers = array($name => $value) to allow parsing
9220
 * @param array  $data_file            (path and filename)
9221
 * @param bool   $embedded_image       True for attaching a embedded file inside content html (optional)
9222
 * @param array  $additionalParameters
9223
 * @param string $sendErrorTo          If there's an error while sending the email, $sendErrorTo will receive a notification
9224
 *
9225
 * @return int true if mail was sent
9226
 *
9227
 * @see             PHPMailer.php
9228
 */
9229
function api_mail_html(
9230
    $recipient_name,
9231
    $recipient_email,
9232
    $subject,
9233
    $message,
9234
    $senderName = '',
9235
    $senderEmail = '',
9236
    $extra_headers = [],
9237
    $data_file = [],
9238
    $embedded_image = false,
9239
    $additionalParameters = [],
9240
    $sendErrorTo = ''
9241
) {
9242
    global $platform_email;
9243
9244
    if (true === api_get_configuration_value('disable_send_mail')) {
9245
        return true;
9246
    }
9247
9248
    $mail = new PHPMailer();
9249
    $mail->Mailer = $platform_email['SMTP_MAILER'];
9250
    $mail->Host = $platform_email['SMTP_HOST'];
9251
    $mail->Port = $platform_email['SMTP_PORT'];
9252
    $mail->CharSet = isset($platform_email['SMTP_CHARSET']) ? $platform_email['SMTP_CHARSET'] : 'UTF-8';
9253
    // Stay far below SMTP protocol 980 chars limit.
9254
    $mail->WordWrap = 200;
9255
    $mail->SMTPOptions = $platform_email['SMTPOptions'] ?? [];
9256
9257
    if ($platform_email['SMTP_AUTH']) {
9258
        $mail->SMTPAuth = 1;
9259
        $mail->Username = $platform_email['SMTP_USER'];
9260
        $mail->Password = $platform_email['SMTP_PASS'];
9261
        if (isset($platform_email['SMTP_SECURE'])) {
9262
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
9263
        }
9264
    }
9265
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
9266
9267
    // 5 = low, 1 = high
9268
    $mail->Priority = 3;
9269
    $mail->SMTPKeepAlive = true;
9270
9271
    api_set_noreply_and_from_address_to_mailer(
9272
        $mail,
9273
        ['name' => $senderName, 'email' => $senderEmail],
9274
        !empty($extra_headers['reply_to']) ? $extra_headers['reply_to'] : []
9275
    );
9276
9277
    if (!empty($sendErrorTo) && PHPMailer::ValidateAddress($sendErrorTo)) {
9278
        $mail->AddCustomHeader('Errors-To', $sendErrorTo);
9279
    }
9280
9281
    unset($extra_headers['reply_to']);
9282
9283
    $mail->Subject = $subject;
9284
    $mail->AltBody = strip_tags(
9285
        str_replace('<br />', "\n", api_html_entity_decode($message))
9286
    );
9287
9288
    $list = api_get_configuration_value('send_all_emails_to');
9289
    if (!empty($list) && isset($list['emails'])) {
9290
        foreach ($list['emails'] as $email) {
9291
            $mail->AddAddress($email);
9292
        }
9293
    }
9294
9295
    // Send embedded image.
9296
    if ($embedded_image) {
9297
        // Get all images html inside content.
9298
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
9299
        // Prepare new tag images.
9300
        $new_images_html = [];
9301
        $i = 1;
9302
        if (!empty($m[1])) {
9303
            foreach ($m[1] as $image_path) {
9304
                $real_path = realpath($image_path);
9305
                $filename = basename($image_path);
9306
                $image_cid = $filename.'_'.$i;
9307
                $encoding = 'base64';
9308
                $image_type = mime_content_type($real_path);
9309
                $mail->AddEmbeddedImage(
9310
                    $real_path,
9311
                    $image_cid,
9312
                    $filename,
9313
                    $encoding,
9314
                    $image_type
9315
                );
9316
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
9317
                $i++;
9318
            }
9319
        }
9320
9321
        // Replace origin image for new embedded image html.
9322
        $x = 0;
9323
        if (!empty($m[0])) {
9324
            foreach ($m[0] as $orig_img) {
9325
                $message = str_replace($orig_img, $new_images_html[$x], $message);
9326
                $x++;
9327
            }
9328
        }
9329
    }
9330
9331
    $mailView = new Template(null, false, false, false, false, false, false);
9332
9333
    $noReply = api_get_setting('noreply_email_address');
9334
    if (!empty($noReply)) {
9335
        $message .= '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
9336
    }
9337
    $mailView->assign('content', $message);
9338
9339
    if (isset($additionalParameters['link'])) {
9340
        $mailView->assign('link', $additionalParameters['link']);
9341
    }
9342
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
9343
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
9344
    $layout = $mailView->get_template('mail/mail.tpl');
9345
    $mail->Body = $mailView->fetch($layout);
9346
9347
    // Attachment.
9348
    if (!empty($data_file)) {
9349
        foreach ($data_file as $file_attach) {
9350
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
9351
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
9352
            }
9353
        }
9354
    }
9355
9356
    // Only valid addresses are accepted.
9357
    if (is_array($recipient_email)) {
9358
        foreach ($recipient_email as $dest) {
9359
            if (api_valid_email($dest)) {
9360
                $mail->AddAddress($dest, $recipient_name);
9361
            }
9362
        }
9363
    } else {
9364
        if (api_valid_email($recipient_email)) {
9365
            $mail->AddAddress($recipient_email, $recipient_name);
9366
        } else {
9367
            return 0;
9368
        }
9369
    }
9370
9371
    if (is_array($extra_headers) && count($extra_headers) > 0) {
9372
        foreach ($extra_headers as $key => $value) {
9373
            switch (strtolower($key)) {
9374
                case 'encoding':
9375
                case 'content-transfer-encoding':
9376
                    $mail->Encoding = $value;
9377
                    break;
9378
                case 'charset':
9379
                    $mail->CharSet = $value;
9380
                    break;
9381
                case 'contenttype':
9382
                case 'content-type':
9383
                    $mail->ContentType = $value;
9384
                    break;
9385
                default:
9386
                    $mail->AddCustomHeader($key, $value);
9387
                    break;
9388
            }
9389
        }
9390
    } else {
9391
        if (!empty($extra_headers)) {
9392
            $mail->AddCustomHeader($extra_headers);
9393
        }
9394
    }
9395
9396
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
9397
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
9398
9399
    if (!empty($platform_email['DKIM']) &&
9400
        !empty($platform_email['DKIM_SELECTOR']) &&
9401
        !empty($platform_email['DKIM_DOMAIN']) &&
9402
        (!empty($platform_email['DKIM_PRIVATE_KEY_STRING']) || !empty($platform_email['DKIM_PRIVATE_KEY']))) {
9403
        $mail->DKIM_selector = $platform_email['DKIM_SELECTOR'];
9404
        $mail->DKIM_domain = $platform_email['DKIM_DOMAIN'];
9405
        if (!empty($platform_email['SMTP_UNIQUE_SENDER'])) {
9406
            $mail->DKIM_identity = $platform_email['SMTP_FROM_EMAIL'];
9407
        }
9408
        $mail->DKIM_private_string = $platform_email['DKIM_PRIVATE_KEY_STRING'];
9409
        $mail->DKIM_private = $platform_email['DKIM_PRIVATE_KEY'];
9410
    }
9411
9412
    // Send the mail message.
9413
    $sent = $mail->Send();
9414
    if (!$sent) {
9415
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
9416
    }
9417
9418
    if ($mail->SMTPDebug > 1) {
9419
        error_log(
9420
            "Mail debug:: ".
9421
            "Protocol: ".$mail->Mailer.' :: '.
9422
            "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
9423
            "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
9424
            ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
9425
            "Sender: ".$mail->Sender.
9426
            "Recipient email: ".$recipient_email.
9427
            "Subject: ".$subject
9428
        );
9429
    }
9430
9431
    if (!$sent) {
9432
        return 0;
9433
    }
9434
9435
    if (!empty($additionalParameters)) {
9436
        $plugin = new AppPlugin();
9437
        $smsPlugin = $plugin->getSMSPluginLibrary();
9438
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
9439
            $smsPlugin->send($additionalParameters);
9440
        }
9441
    }
9442
9443
    // Clear all the addresses.
9444
    $mail->ClearAddresses();
9445
9446
    // Clear all attachments
9447
    $mail->ClearAttachments();
9448
9449
    return 1;
9450
}
9451
9452
/**
9453
 * Checks access to a course group.
9454
 *
9455
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
9456
 * @param bool   $showHeader
9457
 */
9458
function api_protect_course_group($tool, $showHeader = true)
9459
{
9460
    $groupId = api_get_group_id();
9461
    if (!empty($groupId)) {
9462
        if (api_is_platform_admin()) {
9463
            return true;
9464
        }
9465
9466
        if (api_is_allowed_to_edit(false, true, true)) {
9467
            return true;
9468
        }
9469
9470
        $userId = api_get_user_id();
9471
        $sessionId = api_get_session_id();
9472
        if (!empty($sessionId)) {
9473
            if (api_is_coach($sessionId, api_get_course_int_id())) {
9474
                return true;
9475
            }
9476
9477
            if (api_is_drh()) {
9478
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
9479
                    return true;
9480
                }
9481
            }
9482
        }
9483
9484
        $groupInfo = GroupManager::get_group_properties($groupId);
9485
9486
        // Group doesn't exists
9487
        if (empty($groupInfo)) {
9488
            api_not_allowed($showHeader);
9489
        }
9490
9491
        // Check group access
9492
        $allow = GroupManager::user_has_access(
9493
            $userId,
9494
            $groupInfo['iid'],
9495
            $tool
9496
        );
9497
9498
        if (!$allow) {
9499
            api_not_allowed($showHeader);
9500
        }
9501
    }
9502
9503
    return false;
9504
}
9505
9506
/**
9507
 * Check if a date is in a date range.
9508
 *
9509
 * @param datetime $startDate
9510
 * @param datetime $endDate
9511
 * @param datetime $currentDate
9512
 *
9513
 * @return bool true if date is in rage, false otherwise
9514
 */
9515
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9516
{
9517
    $startDate = strtotime(api_get_local_time($startDate));
9518
    $endDate = strtotime(api_get_local_time($endDate));
9519
    $currentDate = strtotime(api_get_local_time($currentDate));
9520
9521
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9522
        return true;
9523
    }
9524
9525
    return false;
9526
}
9527
9528
/**
9529
 * Eliminate the duplicates of a multidimensional array by sending the key.
9530
 *
9531
 * @param array $array multidimensional array
9532
 * @param int   $key   key to find to compare
9533
 *
9534
 * @return array
9535
 */
9536
function api_unique_multidim_array($array, $key)
9537
{
9538
    $temp_array = [];
9539
    $i = 0;
9540
    $key_array = [];
9541
9542
    foreach ($array as $val) {
9543
        if (!in_array($val[$key], $key_array)) {
9544
            $key_array[$i] = $val[$key];
9545
            $temp_array[$i] = $val;
9546
        }
9547
        $i++;
9548
    }
9549
9550
    return $temp_array;
9551
}
9552
9553
/**
9554
 * Limit the access to Session Admins when the limit_session_admin_role
9555
 * configuration variable is set to true.
9556
 */
9557
function api_protect_limit_for_session_admin()
9558
{
9559
    $limitAdmin = api_get_setting('limit_session_admin_role');
9560
    if (api_is_session_admin() && $limitAdmin === 'true') {
9561
        api_not_allowed(true);
9562
    }
9563
}
9564
9565
/**
9566
 * Limits that a session admin has access to list users.
9567
 * When limit_session_admin_list_users configuration variable is set to true.
9568
 */
9569
function api_protect_session_admin_list_users()
9570
{
9571
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
9572
9573
    if (api_is_session_admin() && true === $limitAdmin) {
9574
        api_not_allowed(true);
9575
    }
9576
}
9577
9578
/**
9579
 * @return bool
9580
 */
9581
function api_is_student_view_active()
9582
{
9583
    $studentView = Session::read('studentview');
9584
9585
    return $studentView == 'studentview';
9586
}
9587
9588
/**
9589
 * Adds a file inside the upload/$type/id.
9590
 *
9591
 * @param string $type
9592
 * @param array  $file
9593
 * @param int    $itemId
9594
 * @param string $cropParameters
9595
 *
9596
 * @return array|bool
9597
 */
9598
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9599
{
9600
    $upload = process_uploaded_file($file);
9601
    if ($upload) {
9602
        $name = api_replace_dangerous_char($file['name']);
9603
9604
        // No "dangerous" files
9605
        $name = disable_dangerous_file($name);
9606
9607
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9608
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9609
9610
        if (!is_dir($path)) {
9611
            mkdir($path, api_get_permissions_for_new_directories(), true);
9612
        }
9613
9614
        $pathToSave = $path.$name;
9615
        $result = moveUploadedFile($file, $pathToSave);
9616
9617
        if ($result) {
9618
            if (!empty($cropParameters)) {
9619
                $image = new Image($pathToSave);
9620
                $image->crop($cropParameters);
9621
            }
9622
9623
            return ['path_to_save' => $pathId.$name];
9624
        }
9625
    }
9626
9627
    return false;
9628
}
9629
9630
/**
9631
 * @param string $type
9632
 * @param int    $itemId
9633
 * @param string $file
9634
 *
9635
 * @return bool
9636
 */
9637
function api_get_uploaded_web_url($type, $itemId, $file)
9638
{
9639
    return api_get_uploaded_file($type, $itemId, $file, true);
9640
}
9641
9642
/**
9643
 * @param string $type
9644
 * @param int    $itemId
9645
 * @param string $file
9646
 * @param bool   $getUrl
9647
 *
9648
 * @return bool
9649
 */
9650
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9651
{
9652
    $itemId = (int) $itemId;
9653
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9654
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9655
    $file = basename($file);
9656
    $file = $path.'/'.$file;
9657
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9658
        if ($getUrl) {
9659
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
9660
        }
9661
9662
        return $file;
9663
    }
9664
9665
    return false;
9666
}
9667
9668
/**
9669
 * @param string $type
9670
 * @param int    $itemId
9671
 * @param string $file
9672
 * @param string $title
9673
 */
9674
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9675
{
9676
    $file = api_get_uploaded_file($type, $itemId, $file);
9677
    if ($file) {
9678
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9679
            DocumentManager::file_send_for_download($file, true, $title);
9680
            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...
9681
        }
9682
    }
9683
    api_not_allowed(true);
9684
}
9685
9686
/**
9687
 * @param string $type
9688
 * @param string $file
9689
 */
9690
function api_remove_uploaded_file($type, $file)
9691
{
9692
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9693
    $path = $typePath.'/'.$file;
9694
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9695
        unlink($path);
9696
    }
9697
}
9698
9699
/**
9700
 * @param string $type
9701
 * @param int    $itemId
9702
 * @param string $file
9703
 *
9704
 * @return bool
9705
 */
9706
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9707
{
9708
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9709
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9710
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9711
        unlink($file);
9712
9713
        return true;
9714
    }
9715
9716
    return false;
9717
}
9718
9719
/**
9720
 * Converts string value to float value.
9721
 *
9722
 * 3.141516 => 3.141516
9723
 * 3,141516 => 3.141516
9724
 *
9725
 * @todo WIP
9726
 *
9727
 * @param string $number
9728
 *
9729
 * @return float
9730
 */
9731
function api_float_val($number)
9732
{
9733
    $number = (float) str_replace(',', '.', trim($number));
9734
9735
    return $number;
9736
}
9737
9738
/**
9739
 * Converts float values
9740
 * Example if $decimals = 2.
9741
 *
9742
 * 3.141516 => 3.14
9743
 * 3,141516 => 3,14
9744
 *
9745
 * @param string $number            number in iso code
9746
 * @param int    $decimals
9747
 * @param string $decimalSeparator
9748
 * @param string $thousandSeparator
9749
 *
9750
 * @return bool|string
9751
 */
9752
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9753
{
9754
    $number = api_float_val($number);
9755
9756
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9757
}
9758
9759
/**
9760
 * Set location url with a exit break by default.
9761
 *
9762
 * @param string $url
9763
 * @param bool   $exit
9764
 */
9765
function api_location($url, $exit = true)
9766
{
9767
    header('Location: '.$url);
9768
9769
    if ($exit) {
9770
        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...
9771
    }
9772
}
9773
9774
/**
9775
 * @return string
9776
 */
9777
function api_get_web_url()
9778
{
9779
    if (api_get_setting('server_type') === 'test') {
9780
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9781
    } else {
9782
        return api_get_path(WEB_PATH).'web/';
9783
    }
9784
}
9785
9786
/**
9787
 * @param string $from
9788
 * @param string $to
9789
 *
9790
 * @return string
9791
 */
9792
function api_get_relative_path($from, $to)
9793
{
9794
    // some compatibility fixes for Windows paths
9795
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9796
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9797
    $from = str_replace('\\', '/', $from);
9798
    $to = str_replace('\\', '/', $to);
9799
9800
    $from = explode('/', $from);
9801
    $to = explode('/', $to);
9802
    $relPath = $to;
9803
9804
    foreach ($from as $depth => $dir) {
9805
        // find first non-matching dir
9806
        if ($dir === $to[$depth]) {
9807
            // ignore this directory
9808
            array_shift($relPath);
9809
        } else {
9810
            // get number of remaining dirs to $from
9811
            $remaining = count($from) - $depth;
9812
            if ($remaining > 1) {
9813
                // add traversals up to first matching dir
9814
                $padLength = (count($relPath) + $remaining - 1) * -1;
9815
                $relPath = array_pad($relPath, $padLength, '..');
9816
                break;
9817
            } else {
9818
                $relPath[0] = './'.$relPath[0];
9819
            }
9820
        }
9821
    }
9822
9823
    return implode('/', $relPath);
9824
}
9825
9826
/**
9827
 * Unserialize content using Brummann\Polyfill\Unserialize.
9828
 *
9829
 * @param string $type
9830
 * @param string $serialized
9831
 *
9832
 * @return mixed
9833
 */
9834
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9835
{
9836
    switch ($type) {
9837
        case 'career':
9838
        case 'sequence_graph':
9839
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9840
            break;
9841
        case 'lp':
9842
            $allowedClasses = [
9843
                learnpath::class,
9844
                learnpathItem::class,
9845
                aicc::class,
9846
                aiccBlock::class,
9847
                aiccItem::class,
9848
                aiccObjective::class,
9849
                aiccResource::class,
9850
                scorm::class,
9851
                scormItem::class,
9852
                scormMetadata::class,
9853
                scormOrganization::class,
9854
                scormResource::class,
9855
                Link::class,
9856
                LpItem::class,
9857
            ];
9858
            break;
9859
        case 'course':
9860
            $allowedClasses = [
9861
                Course::class,
9862
                Announcement::class,
9863
                Attendance::class,
9864
                CalendarEvent::class,
9865
                CourseCopyLearnpath::class,
9866
                CourseCopyTestCategory::class,
9867
                CourseDescription::class,
9868
                CourseSession::class,
9869
                Document::class,
9870
                Forum::class,
9871
                ForumCategory::class,
9872
                ForumPost::class,
9873
                ForumTopic::class,
9874
                Glossary::class,
9875
                GradeBookBackup::class,
9876
                Link::class,
9877
                LinkCategory::class,
9878
                Quiz::class,
9879
                QuizQuestion::class,
9880
                QuizQuestionOption::class,
9881
                ScormDocument::class,
9882
                Survey::class,
9883
                SurveyInvitation::class,
9884
                SurveyQuestion::class,
9885
                Thematic::class,
9886
                ToolIntro::class,
9887
                Wiki::class,
9888
                Work::class,
9889
                stdClass::class,
9890
            ];
9891
            break;
9892
        case 'not_allowed_classes':
9893
        default:
9894
            $allowedClasses = false;
9895
    }
9896
9897
    if ($ignoreErrors) {
9898
        return @Unserialize::unserialize(
9899
            $serialized,
9900
            ['allowed_classes' => $allowedClasses]
9901
        );
9902
    }
9903
9904
    return Unserialize::unserialize(
9905
        $serialized,
9906
        ['allowed_classes' => $allowedClasses]
9907
    );
9908
}
9909
9910
/**
9911
 * Set the From and ReplyTo properties to PHPMailer instance.
9912
 *
9913
 * @throws \PHPMailer\PHPMailer\Exception
9914
 */
9915
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])
9916
{
9917
    $platformEmail = $GLOBALS['platform_email'];
9918
9919
    $noReplyAddress = api_get_setting('noreply_email_address');
9920
    $avoidReplyToAddress = false;
9921
9922
    if (!empty($noReplyAddress)) {
9923
        $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
9924
    }
9925
9926
    $notification = new Notification();
9927
    // If the parameter is set don't use the admin.
9928
    $senderName = !empty($sender['name']) ? $sender['name'] : $notification->getDefaultPlatformSenderName();
9929
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $notification->getDefaultPlatformSenderEmail();
9930
9931
    // Send errors to the platform admin
9932
    $adminEmail = api_get_setting('emailAdministrator');
9933
    if (PHPMailer::ValidateAddress($adminEmail)) {
9934
        $mailer->AddCustomHeader('Errors-To: '.$adminEmail);
9935
    }
9936
9937
    // Reply to first
9938
    if (!$avoidReplyToAddress) {
9939
        if (
9940
            !empty($replyToAddress) &&
9941
            PHPMailer::ValidateAddress($replyToAddress['mail'])
9942
        ) {
9943
            $mailer->AddReplyTo($replyToAddress['mail'], $replyToAddress['name']);
9944
            //$mailer->Sender = $replyToAddress['mail'];
9945
        }
9946
    }
9947
9948
    //If the SMTP configuration only accept one sender
9949
    if (
9950
        isset($platformEmail['SMTP_UNIQUE_SENDER']) &&
9951
        $platformEmail['SMTP_UNIQUE_SENDER']
9952
    ) {
9953
        $senderName = $notification->getDefaultPlatformSenderName();
9954
        $senderEmail = $notification->getDefaultPlatformSenderEmail();
9955
9956
        if (PHPMailer::ValidateAddress($senderEmail)) {
9957
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
9958
            $mailer->Sender = $senderEmail;
9959
        }
9960
    }
9961
9962
    $mailer->SetFrom($senderEmail, $senderName, !$avoidReplyToAddress);
9963
}
9964
9965
/**
9966
 * @param string $template
9967
 *
9968
 * @return string
9969
 */
9970
function api_find_template($template)
9971
{
9972
    return Template::findTemplateFilePath($template);
9973
}
9974
9975
/**
9976
 * Returns an array of languages (English names like "english", "french", etc)
9977
 * to ISO 639-1 codes (fr, es, etc) for use (for example) to show flags
9978
 * Note: 'english' is returned as 'gb'.
9979
 *
9980
 * @return array
9981
 */
9982
function api_get_language_list_for_flag()
9983
{
9984
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9985
    $sql = "SELECT english_name, isocode FROM $table
9986
            ORDER BY original_name ASC";
9987
    static $languages = [];
9988
    if (empty($languages)) {
9989
        $result = Database::query($sql);
9990
        while ($row = Database::fetch_array($result)) {
9991
            $languages[$row['english_name']] = $row['isocode'];
9992
        }
9993
        $languages['english'] = 'gb';
9994
    }
9995
9996
    return $languages;
9997
}
9998
9999
/**
10000
 * Generate the Javascript required for the on-page translation of
10001
 * multi-language strings.
10002
 *
10003
 * @throws Exception
10004
 *
10005
 * @return string
10006
 */
10007
function api_get_language_translate_html()
10008
{
10009
    $translate = api_get_configuration_value('translate_html');
10010
10011
    if (!$translate) {
10012
        return '';
10013
    }
10014
10015
    $languageList = api_get_languages();
10016
    $hideAll = '';
10017
    foreach ($languageList['all'] as $language) {
10018
        $hideAll .= '
10019
        $("span:lang('.$language['isocode'].')").filter(
10020
            function(e, val) {
10021
                // Only find the spans if they have set the lang
10022
                if ($(this).attr("lang") == null) {
10023
                    return false;
10024
                }
10025
10026
                // Ignore ckeditor classes
10027
                return !this.className.match(/cke(.*)/);
10028
        }).hide();'."\n";
10029
    }
10030
10031
    $userInfo = api_get_user_info();
10032
    $languageId = 0;
10033
    if (!empty($userInfo['language'])) {
10034
        $languageId = api_get_language_id($userInfo['language']);
10035
    } elseif (!empty($_GET['language'])) {
10036
        $languageId = api_get_language_id($_GET['language']);
10037
    }
10038
    $languageInfo = api_get_language_info($languageId);
10039
    $isoCode = 'en';
10040
10041
    if (!empty($languageInfo)) {
10042
        $isoCode = $languageInfo['isocode'];
10043
    }
10044
10045
    return '
10046
            $(function() {
10047
                '.$hideAll.'
10048
                var defaultLanguageFromUser = "'.$isoCode.'";
10049
10050
                $("span:lang('.$isoCode.')").filter(
10051
                    function() {
10052
                        // Ignore ckeditor classes
10053
                        return !this.className.match(/cke(.*)/);
10054
                }).show();
10055
10056
                var defaultLanguage = "";
10057
                var langFromUserFound = false;
10058
10059
                $(this).find("span").filter(
10060
                    function() {
10061
                        // Ignore ckeditor classes
10062
                        return !this.className.match(/cke(.*)/);
10063
                }).each(function() {
10064
                    defaultLanguage = $(this).attr("lang");
10065
                    if (defaultLanguage) {
10066
                        $(this).before().next("br").remove();
10067
                        if (defaultLanguageFromUser == defaultLanguage) {
10068
                            langFromUserFound = true;
10069
                        }
10070
                    }
10071
                });
10072
10073
                // Show default language
10074
                if (langFromUserFound == false && defaultLanguage) {
10075
                    $("span:lang("+defaultLanguage+")").filter(
10076
                    function() {
10077
                            // Ignore ckeditor classes
10078
                            return !this.className.match(/cke(.*)/);
10079
                    }).show();
10080
                }
10081
            });
10082
    ';
10083
}
10084
10085
/**
10086
 * Filter a multi-language HTML string (for the multi-language HTML
10087
 * feature) into the given language (strip the rest).
10088
 *
10089
 * @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>
10090
 * @param string $language   The language in which we want to get the
10091
 *
10092
 * @throws Exception
10093
 *
10094
 * @return string The filtered string in the given language, or the full string if no translated string was identified
10095
 */
10096
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
10097
{
10098
    if (api_get_configuration_value('translate_html') != true) {
10099
        return $htmlString;
10100
    }
10101
    $userInfo = api_get_user_info();
10102
    $languageId = 0;
10103
    if (!empty($language)) {
10104
        $languageId = api_get_language_id($language);
10105
    } elseif (!empty($userInfo['language'])) {
10106
        $languageId = api_get_language_id($userInfo['language']);
10107
    }
10108
    $languageInfo = api_get_language_info($languageId);
10109
    $isoCode = 'en';
10110
10111
    if (!empty($languageInfo)) {
10112
        $isoCode = $languageInfo['isocode'];
10113
    }
10114
10115
    // Split HTML in the separate language strings
10116
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
10117
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
10118
        return $htmlString;
10119
    }
10120
    $matches = [];
10121
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
10122
    if (!empty($matches)) {
10123
        // matches[0] are the full string
10124
        // matches[1] are the languages
10125
        // matches[2] are the strings
10126
        foreach ($matches[1] as $id => $match) {
10127
            if ($match == $isoCode) {
10128
                return $matches[2][$id];
10129
            }
10130
        }
10131
        // Could find the pattern but could not find our language. Return the first language found.
10132
        return $matches[2][0];
10133
    }
10134
    // Could not find pattern. Just return the whole string. We shouldn't get here.
10135
    return $htmlString;
10136
}
10137
10138
/**
10139
 * Get the print.css file for current theme.
10140
 * Only the file path or the file contents when $getFileContents is true.
10141
 */
10142
function api_get_print_css(bool $getFileContents = true, bool $useWebPath = false): string
10143
{
10144
    $sysCssPath = api_get_path(SYS_CSS_PATH);
10145
    $cssFile = $sysCssPath.'themes/'.api_get_visual_theme().'/print.css';
10146
10147
    if (!file_exists($cssFile)) {
10148
        $cssFile = $sysCssPath.'print.css';
10149
    }
10150
10151
    if ($getFileContents) {
10152
        return file_get_contents($cssFile);
10153
    }
10154
10155
    if ($useWebPath) {
10156
        return str_replace($sysCssPath, api_get_path(WEB_CSS_PATH), $cssFile);
10157
    }
10158
10159
    return $cssFile;
10160
}
10161
10162
function api_protect_webservices()
10163
{
10164
    if (api_get_configuration_value('disable_webservices')) {
10165
        echo "Webservices are disabled. \n";
10166
        echo "To enable, add \$_configuration['disable_webservices'] = true; in configuration.php";
10167
        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...
10168
    }
10169
}
10170