Passed
Push — 1.11.x ( bbf69b...6dc81d )
by Julito
14:17 queued 10s
created

api_get_current_access_url_id()   B

Complexity

Conditions 7
Paths 11

Size

Total Lines 40
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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