Passed
Push — master ( c2ca82...a41561 )
by Julito
11:30
created

api_get_bootstrap_and_font_awesome()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1134
function api_protect_course_script($print_headers = false, $allow_session_admins = false, /** @scrutinizer ignore-unused */ $allow_drh = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1135
{
1136
    $is_allowed_in_course = api_is_allowed_in_course();
1137
1138
    $is_visible = false;
1139
    $course_info = api_get_course_info();
1140
1141
    if (empty($course_info)) {
1142
        api_not_allowed($print_headers);
1143
1144
        return false;
1145
    }
1146
1147
    if (api_is_drh()) {
1148
        return true;
1149
    }
1150
1151
    // Session admin has access to course
1152
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1153
    if ($sessionAccess) {
1154
        $allow_session_admins = true;
1155
    }
1156
1157
    if (api_is_platform_admin($allow_session_admins)) {
1158
        return true;
1159
    }
1160
1161
    if (isset($course_info) && isset($course_info['visibility'])) {
1162
        switch ($course_info['visibility']) {
1163
            default:
1164
            case COURSE_VISIBILITY_CLOSED:
1165
                // Completely closed: the course is only accessible to the teachers. - 0
1166
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1167
                    $is_visible = true;
1168
                }
1169
                break;
1170
            case COURSE_VISIBILITY_REGISTERED:
1171
                // Private - access authorized to course members only - 1
1172
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1173
                    $is_visible = true;
1174
                }
1175
                break;
1176
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1177
                // Open - access allowed for users registered on the platform - 2
1178
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1179
                    $is_visible = true;
1180
                }
1181
                break;
1182
            case COURSE_VISIBILITY_OPEN_WORLD:
1183
                //Open - access allowed for the whole world - 3
1184
                $is_visible = true;
1185
                break;
1186
            case COURSE_VISIBILITY_HIDDEN:
1187
                //Completely closed: the course is only accessible to the teachers. - 0
1188
                if (api_is_platform_admin()) {
1189
                    $is_visible = true;
1190
                }
1191
                break;
1192
        }
1193
1194
        //If password is set and user is not registered to the course then the course is not visible
1195
        if ($is_allowed_in_course == 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...
1196
            isset($course_info['registration_code']) &&
1197
            !empty($course_info['registration_code'])
1198
        ) {
1199
            $is_visible = false;
1200
        }
1201
    }
1202
1203
    // Check session visibility
1204
    $session_id = api_get_session_id();
1205
1206
    if (!empty($session_id)) {
1207
        //$is_allowed_in_course was set in local.inc.php
1208
        if (!$is_allowed_in_course) {
1209
            $is_visible = false;
1210
        }
1211
    }
1212
1213
    if (!$is_visible) {
1214
        api_not_allowed($print_headers);
1215
1216
        return false;
1217
    }
1218
1219
    return true;
1220
}
1221
1222
/**
1223
 * Function used to protect an admin script.
1224
 *
1225
 * The function blocks access when the user has no platform admin rights
1226
 * with an error message printed on default output
1227
 *
1228
 * @param bool Whether to allow session admins as well
1229
 * @param bool Whether to allow HR directors as well
1230
 * @param string An optional message (already passed through get_lang)
1231
 *
1232
 * @return bool True if user is allowed, false otherwise.
1233
 *              The function also outputs an error message in case not allowed
1234
 *
1235
 * @author Roan Embrechts (original author)
1236
 */
1237
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1238
{
1239
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1240
        api_not_allowed(true, $message);
1241
1242
        return false;
1243
    }
1244
1245
    return true;
1246
}
1247
1248
/**
1249
 * Function used to protect a teacher script.
1250
 * The function blocks access when the user has no teacher rights.
1251
 *
1252
 * @author Yoselyn Castillo
1253
 */
1254
function api_protect_teacher_script($allow_sessions_admins = false)
0 ignored issues
show
Unused Code introduced by
The parameter $allow_sessions_admins is not used and could be removed. ( Ignorable by Annotation )

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

1254
function api_protect_teacher_script(/** @scrutinizer ignore-unused */ $allow_sessions_admins = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1255
{
1256
    if (!api_is_allowed_to_edit()) {
1257
        api_not_allowed(true);
1258
1259
        return false;
1260
    }
1261
1262
    return true;
1263
}
1264
1265
/**
1266
 * Function used to prevent anonymous users from accessing a script.
1267
 *
1268
 * @param bool|true $printHeaders
1269
 *
1270
 * @author Roan Embrechts
1271
 *
1272
 * @return bool
1273
 */
1274
function api_block_anonymous_users($printHeaders = true)
1275
{
1276
    $user = api_get_user_info();
1277
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1278
        api_not_allowed($printHeaders);
1279
1280
        return false;
1281
    }
1282
1283
    return true;
1284
}
1285
1286
/**
1287
 * Returns a rough evaluation of the browser's name and version based on very
1288
 * simple regexp.
1289
 *
1290
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1291
 */
1292
function api_get_navigator()
1293
{
1294
    $navigator = 'Unknown';
1295
    $version = 0;
1296
1297
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1298
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1299
    }
1300
1301
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1302
        $navigator = 'Opera';
1303
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1304
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1305
        $navigator = 'Edge';
1306
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1307
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1308
        $navigator = 'Internet Explorer';
1309
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1310
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1311
        $navigator = 'Chrome';
1312
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1313
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1314
        $navigator = 'Safari';
1315
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1316
            // If this Safari does have the "Version/" string in its user agent
1317
            // then use that as a version indicator rather than what's after
1318
            // "Safari/" which is rather a "build number" or something
1319
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1320
        } else {
1321
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1322
        }
1323
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1324
        $navigator = 'Firefox';
1325
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1326
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1327
        $navigator = 'Netscape';
1328
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1329
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1330
        } else {
1331
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1332
        }
1333
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1334
        $navigator = 'Konqueror';
1335
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1336
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1337
        $navigator = 'AppleWebKit';
1338
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1339
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1340
        $navigator = 'Mozilla';
1341
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1342
    }
1343
1344
    // Now cut extra stuff around (mostly *after*) the version number
1345
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1346
1347
    if (strpos($version, '.') === false) {
1348
        $version = number_format(doubleval($version), 1);
1349
    }
1350
    $return = ['name' => $navigator, 'version' => $version];
1351
1352
    return $return;
1353
}
1354
1355
/**
1356
 * @return true if user self registration is allowed, false otherwise
1357
 */
1358
function api_is_self_registration_allowed()
1359
{
1360
    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...
1361
}
1362
1363
/**
1364
 * This function returns the id of the user which is stored in the $_user array.
1365
 *
1366
 * example: The function can be used to check if a user is logged in
1367
 *          if (api_get_user_id())
1368
 *
1369
 * @return int the id of the current user, 0 if is empty
1370
 */
1371
function api_get_user_id()
1372
{
1373
    $userInfo = Session::read('_user');
1374
    if ($userInfo && isset($userInfo['user_id'])) {
1375
        return (int) $userInfo['user_id'];
1376
    }
1377
1378
    return 0;
1379
}
1380
1381
/**
1382
 * Gets the list of courses a specific user is subscribed to.
1383
 *
1384
 * @param int       User ID
1385
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1386
 *
1387
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1388
 *
1389
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1390
 */
1391
function api_get_user_courses($userId, $fetch_session = true)
0 ignored issues
show
Unused Code introduced by
The parameter $fetch_session is not used and could be removed. ( Ignorable by Annotation )

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

1391
function api_get_user_courses($userId, /** @scrutinizer ignore-unused */ $fetch_session = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1392
{
1393
    // Get out if not integer
1394
    if ($userId != strval(intval($userId))) {
1395
        return [];
1396
    }
1397
1398
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1399
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1400
1401
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1402
            FROM $t_course cc, $t_course_user cu
1403
            WHERE
1404
                cc.id = cu.c_id AND
1405
                cu.user_id = $userId AND
1406
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1407
    $result = Database::query($sql);
1408
    if ($result === false) {
1409
        return [];
1410
    }
1411
1412
    $courses = [];
1413
    while ($row = Database::fetch_array($result)) {
1414
        // we only need the database name of the course
1415
        $courses[] = $row;
1416
    }
1417
1418
    return $courses;
1419
}
1420
1421
/**
1422
 * Formats user information into a standard array
1423
 * This function should be only used inside api_get_user_info().
1424
 *
1425
 * @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...
1426
 * @param bool $add_password
1427
 * @param bool $loadAvatars  turn off to improve performance
1428
 *
1429
 * @return array Standard user array
1430
 */
1431
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1432
{
1433
    $result = [];
1434
1435
    if (!isset($user['user_id'])) {
1436
        return [];
1437
    }
1438
1439
    $result['firstname'] = null;
1440
    $result['lastname'] = null;
1441
1442
    if (isset($user['firstname']) && isset($user['lastname'])) {
1443
        // with only lowercase
1444
        $result['firstname'] = $user['firstname'];
1445
        $result['lastname'] = $user['lastname'];
1446
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1447
        // with uppercase letters
1448
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1449
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1450
    }
1451
1452
    if (isset($user['email'])) {
1453
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1454
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1455
    } else {
1456
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1457
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1458
    }
1459
1460
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1461
    $result['complete_name_with_username'] = $result['complete_name'];
1462
1463
    if (!empty($user['username'])) {
1464
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1465
    }
1466
1467
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1468
    if (!empty($user['email'])) {
1469
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1470
        if ($showEmail) {
1471
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1472
        }
1473
    } else {
1474
        $result['complete_name_with_email'] = $result['complete_name'];
1475
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1476
    }
1477
1478
    // Kept for historical reasons
1479
    $result['firstName'] = $result['firstname'];
1480
    $result['lastName'] = $result['lastname'];
1481
1482
    $attributes = [
1483
        'phone',
1484
        'address',
1485
        'picture_uri',
1486
        'official_code',
1487
        'status',
1488
        'active',
1489
        'auth_source',
1490
        'username',
1491
        'theme',
1492
        'language',
1493
        'creator_id',
1494
        'registration_date',
1495
        'hr_dept_id',
1496
        'expiration_date',
1497
        'last_login',
1498
        'user_is_online',
1499
    ];
1500
1501
    if (api_get_setting('extended_profile') === 'true') {
1502
        $attributes[] = 'competences';
1503
        $attributes[] = 'diplomas';
1504
        $attributes[] = 'teach';
1505
        $attributes[] = 'openarea';
1506
    }
1507
1508
    foreach ($attributes as $attribute) {
1509
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1510
    }
1511
1512
    $user_id = (int) $user['user_id'];
1513
    // Maintain the user_id index for backwards compatibility
1514
    $result['user_id'] = $result['id'] = $user_id;
1515
1516
    // Getting user avatar.
1517
    if ($loadAvatars) {
1518
        $result['avatar'] = '';
1519
        $result['avatar_no_query'] = '';
1520
        $result['avatar_small'] = '';
1521
        $result['avatar_medium'] = '';
1522
1523
        if (!isset($user['avatar'])) {
1524
            $originalFile = UserManager::getUserPicture(
1525
                $user_id,
1526
                USER_IMAGE_SIZE_ORIGINAL,
1527
                null,
1528
                $result
1529
            );
1530
            $result['avatar'] = $originalFile;
1531
            $avatarString = explode('?', $result['avatar']);
1532
            $result['avatar_no_query'] = reset($avatarString);
1533
        } else {
1534
            $result['avatar'] = $user['avatar'];
1535
            $avatarString = explode('?', $user['avatar']);
1536
            $result['avatar_no_query'] = reset($avatarString);
1537
        }
1538
1539
        if (!isset($user['avatar_small'])) {
1540
            $smallFile = UserManager::getUserPicture(
1541
                $user_id,
1542
                USER_IMAGE_SIZE_SMALL,
1543
                null,
1544
                $result
1545
            );
1546
            $result['avatar_small'] = $smallFile;
1547
        } else {
1548
            $result['avatar_small'] = $user['avatar_small'];
1549
        }
1550
1551
        if (!isset($user['avatar_medium'])) {
1552
            $mediumFile = UserManager::getUserPicture(
1553
                $user_id,
1554
                USER_IMAGE_SIZE_MEDIUM,
1555
                null,
1556
                $result
1557
            );
1558
            $result['avatar_medium'] = $mediumFile;
1559
        } else {
1560
            $result['avatar_medium'] = $user['avatar_medium'];
1561
        }
1562
    }
1563
1564
    if (isset($user['user_is_online'])) {
1565
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1566
    }
1567
    if (isset($user['user_is_online_in_chat'])) {
1568
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1569
    }
1570
1571
    if ($add_password) {
1572
        $result['password'] = $user['password'];
1573
    }
1574
1575
    if (isset($result['profile_completed'])) {
1576
        $result['profile_completed'] = $user['profile_completed'];
1577
    }
1578
1579
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1580
1581
    // Send message link
1582
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1583
    $result['complete_name_with_message_link'] = Display::url(
1584
        $result['complete_name_with_username'],
1585
        $sendMessage,
1586
        ['class' => 'ajax']
1587
    );
1588
1589
    if (isset($user['extra'])) {
1590
        $result['extra'] = $user['extra'];
1591
    }
1592
1593
    return $result;
1594
}
1595
1596
/**
1597
 * Finds all the information about a user.
1598
 * If no parameter is passed you find all the information about the current user.
1599
 *
1600
 * @param int  $user_id
1601
 * @param bool $checkIfUserOnline
1602
 * @param bool $showPassword
1603
 * @param bool $loadExtraData
1604
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1605
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1606
 * @param bool $updateCache              update apc cache if exists
1607
 *
1608
 * @return array $user_info user_id, lastname, firstname, username, email, etc
1609
 *
1610
 * @author Patrick Cool <[email protected]>
1611
 * @author Julio Montoya
1612
 *
1613
 * @version 21 September 2004
1614
 */
1615
function api_get_user_info(
1616
    $user_id = 0,
1617
    $checkIfUserOnline = false,
1618
    $showPassword = false,
1619
    $loadExtraData = false,
1620
    $loadOnlyVisibleExtraData = false,
1621
    $loadAvatars = true,
1622
    $updateCache = false
1623
) {
1624
    $apcVar = null;
1625
    $user = false;
1626
    $cacheAvailable = api_get_configuration_value('apc');
1627
1628
    if (empty($user_id)) {
1629
        $userFromSession = Session::read('_user');
1630
1631
        if (isset($userFromSession)) {
1632
            if ($cacheAvailable === true) {
1633
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1634
                if (apcu_exists($apcVar)) {
1635
                    if ($updateCache) {
1636
                        apcu_store($apcVar, $userFromSession, 60);
1637
                    }
1638
                    $user = apcu_fetch($apcVar);
1639
                } else {
1640
                    $user = _api_format_user(
1641
                        $userFromSession,
1642
                        $showPassword,
1643
                        $loadAvatars
1644
                    );
1645
                    apcu_store($apcVar, $user, 60);
1646
                }
1647
            } else {
1648
                $user = _api_format_user(
1649
                    $userFromSession,
1650
                    $showPassword,
1651
                    $loadAvatars
1652
                );
1653
            }
1654
1655
            return $user;
1656
        }
1657
1658
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
1659
    }
1660
1661
    // Make sure user_id is safe
1662
    $user_id = (int) $user_id;
1663
1664
    // Re-use user information if not stale and already stored in APCu
1665
    if ($cacheAvailable === true) {
1666
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1667
        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...
1668
            $user = apcu_fetch($apcVar);
1669
1670
            return $user;
1671
        }
1672
    }
1673
1674
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1675
            WHERE id = $user_id";
1676
    $result = Database::query($sql);
1677
    if (Database::num_rows($result) > 0) {
1678
        $result_array = Database::fetch_array($result);
1679
        if ($checkIfUserOnline) {
1680
            $use_status_in_platform = user_is_online($user_id);
1681
            $result_array['user_is_online'] = $use_status_in_platform;
1682
            $user_online_in_chat = 0;
1683
1684
            if ($use_status_in_platform) {
1685
                $user_status = UserManager::get_extra_user_data_by_field(
1686
                    $user_id,
1687
                    'user_chat_status',
1688
                    false,
1689
                    true
1690
                );
1691
                if ((int) $user_status['user_chat_status'] == 1) {
1692
                    $user_online_in_chat = 1;
1693
                }
1694
            }
1695
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1696
        }
1697
1698
        if ($loadExtraData) {
1699
            $fieldValue = new ExtraFieldValue('user');
1700
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1701
                $user_id,
1702
                $loadOnlyVisibleExtraData
1703
            );
1704
        }
1705
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1706
    }
1707
1708
    if ($cacheAvailable === true) {
1709
        apcu_store($apcVar, $user, 60);
1710
    }
1711
1712
    return $user;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $user could also return false which is incompatible with the documented return type array. 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...
1713
}
1714
1715
/**
1716
 * @param int $userId
1717
 *
1718
 * @return User
1719
 */
1720
function api_get_user_entity($userId)
1721
{
1722
    $userId = (int) $userId;
1723
    $repo = UserManager::getRepository();
1724
1725
    /** @var User $user */
1726
    $user = $repo->find($userId);
1727
1728
    return $user;
1729
}
1730
1731
/**
1732
 * Finds all the information about a user from username instead of user id.
1733
 *
1734
 * @param string $username
1735
 *
1736
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1737
 *
1738
 * @author Yannick Warnier <[email protected]>
1739
 */
1740
function api_get_user_info_from_username($username = '')
1741
{
1742
    if (empty($username)) {
1743
        return false;
1744
    }
1745
    $username = trim($username);
1746
1747
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1748
            WHERE username='".Database::escape_string($username)."'";
1749
    $result = Database::query($sql);
1750
    if (Database::num_rows($result) > 0) {
1751
        $resultArray = Database::fetch_array($result);
1752
1753
        return _api_format_user($resultArray);
1754
    }
1755
1756
    return false;
1757
}
1758
1759
/**
1760
 * Get first user with an email.
1761
 *
1762
 * @param string $email
1763
 *
1764
 * @return array|bool
1765
 */
1766
function api_get_user_info_from_email($email = '')
1767
{
1768
    if (empty($email)) {
1769
        return false;
1770
    }
1771
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1772
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1773
    $result = Database::query($sql);
1774
    if (Database::num_rows($result) > 0) {
1775
        $resultArray = Database::fetch_array($result);
1776
1777
        return _api_format_user($resultArray);
1778
    }
1779
1780
    return false;
1781
}
1782
1783
/**
1784
 * @return string
1785
 */
1786
function api_get_course_id()
1787
{
1788
    return Session::read('_cid', null);
1789
}
1790
1791
/**
1792
 * Returns the current course id (integer).
1793
 *
1794
 * @param string $code Optional course code
1795
 *
1796
 * @return int
1797
 */
1798
function api_get_course_int_id($code = null)
1799
{
1800
    if (!empty($code)) {
1801
        $code = Database::escape_string($code);
1802
        $row = Database::select(
1803
            'id',
1804
            Database::get_main_table(TABLE_MAIN_COURSE),
1805
            ['where' => ['code = ?' => [$code]]],
1806
            'first'
1807
        );
1808
1809
        if (is_array($row) && isset($row['id'])) {
1810
            return $row['id'];
1811
        } else {
1812
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
1813
        }
1814
    }
1815
1816
    return Session::read('_real_cid', 0);
1817
}
1818
1819
/**
1820
 * Returns the current course directory.
1821
 *
1822
 * This function relies on api_get_course_info()
1823
 *
1824
 * @param string    The course code - optional (takes it from session if not given)
1825
 *
1826
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1827
 *
1828
 * @author Yannick Warnier <[email protected]>
1829
 */
1830
function api_get_course_path($course_code = null)
1831
{
1832
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1833
1834
    return $info['path'];
1835
}
1836
1837
/**
1838
 * Gets a course setting from the current course_setting table. Try always using integer values.
1839
 *
1840
 * @param string    The name of the setting we want from the table
1841
 * @param string    Optional: course code
1842
 * @param string $setting_name
1843
 *
1844
 * @return mixed The value of that setting in that table. Return -1 if not found.
1845
 */
1846
function api_get_course_setting($setting_name, $course_code = null)
1847
{
1848
    $course_info = api_get_course_info($course_code);
1849
    $table = Database::get_course_table(TABLE_COURSE_SETTING);
1850
    $setting_name = Database::escape_string($setting_name);
1851
    if (!empty($course_info['real_id']) && !empty($setting_name)) {
1852
        $sql = "SELECT value FROM $table
1853
                WHERE c_id = {$course_info['real_id']} AND variable = '$setting_name'";
1854
        $res = Database::query($sql);
1855
        if (Database::num_rows($res) > 0) {
1856
            $row = Database::fetch_array($res);
1857
            if ($setting_name === 'email_alert_manager_on_new_quiz') {
1858
                if (!is_null($row['value'])) {
1859
                    $result = explode(',', $row['value']);
1860
                    $row['value'] = $result;
1861
                }
1862
            }
1863
1864
            return $row['value'];
1865
        }
1866
    }
1867
1868
    return -1;
1869
}
1870
1871
/**
1872
 * Gets an anonymous user ID.
1873
 *
1874
 * For some tools that need tracking, like the learnpath tool, it is necessary
1875
 * to have a usable user-id to enable some kind of tracking, even if not
1876
 * perfect. An anonymous ID is taken from the users table by looking for a
1877
 * status of "6" (anonymous).
1878
 *
1879
 * @return int User ID of the anonymous user, or O if no anonymous user found
1880
 */
1881
function api_get_anonymous_id()
1882
{
1883
    // Find if another anon is connected now
1884
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1885
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1886
    $ip = Database::escape_string(api_get_real_ip());
1887
    $max = api_get_configuration_value('max_anonymous_users');
1888
    if ($max >= 2) {
1889
        $sql = "SELECT * FROM $table as TEL 
1890
                JOIN $tableU as U
1891
                ON U.user_id = TEL.login_user_id
1892
                WHERE TEL.user_ip = '$ip'
1893
                    AND U.status = ".ANONYMOUS."
1894
                    AND U.user_id != 2 ";
1895
1896
        $result = Database::query($sql);
1897
        if (empty(Database::num_rows($result))) {
1898
            $login = uniqid('anon_');
1899
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1900
            if (count($anonList) == $max) {
1901
                foreach ($anonList as $userToDelete) {
1902
                    UserManager::delete_user($userToDelete['user_id']);
1903
                    break;
1904
                }
1905
            }
1906
            $userId = UserManager::create_user(
1907
                $login,
1908
                'anon',
1909
                ANONYMOUS,
1910
                ' anonymous@localhost',
1911
                $login,
1912
                $login
1913
            );
1914
1915
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId 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...
1916
        } else {
1917
            $row = Database::fetch_array($result, 'ASSOC');
1918
1919
            return $row['user_id'];
1920
        }
1921
    }
1922
1923
    $table = Database::get_main_table(TABLE_MAIN_USER);
1924
    $sql = "SELECT user_id 
1925
            FROM $table 
1926
            WHERE status = ".ANONYMOUS." ";
1927
    $res = Database::query($sql);
1928
    if (Database::num_rows($res) > 0) {
1929
        $row = Database::fetch_array($res, 'ASSOC');
1930
1931
        return $row['user_id'];
1932
    }
1933
1934
    // No anonymous user was found.
1935
    return 0;
1936
}
1937
1938
/**
1939
 * @param string $courseCode
1940
 * @param int    $sessionId
1941
 * @param int    $groupId
1942
 *
1943
 * @return string
1944
 */
1945
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1946
{
1947
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1948
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1949
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1950
1951
    $url = 'cidReq='.$courseCode;
1952
    $url .= '&id_session='.$sessionId;
1953
    $url .= '&gidReq='.$groupId;
1954
1955
    return $url;
1956
}
1957
1958
/**
1959
 * Returns the current course url part including session, group, and gradebook params.
1960
 *
1961
 * @param bool   $addSessionId
1962
 * @param bool   $addGroupId
1963
 * @param string $origin
1964
 *
1965
 * @return string Course & session references to add to a URL
1966
 */
1967
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1968
{
1969
    $courseCode = api_get_course_id();
1970
    $url = empty($courseCode) ? '' : 'cidReq='.htmlspecialchars($courseCode);
1971
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1972
1973
    if ($addSessionId) {
1974
        if (!empty($url)) {
1975
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
1976
        }
1977
    }
1978
1979
    if ($addGroupId) {
1980
        if (!empty($url)) {
1981
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
1982
        }
1983
    }
1984
1985
    if (!empty($url)) {
1986
        $url .= '&gradebook='.(int) api_is_in_gradebook();
1987
        $url .= '&origin='.$origin;
1988
    }
1989
1990
    return $url;
1991
}
1992
1993
/**
1994
 * Get if we visited a gradebook page.
1995
 *
1996
 * @return bool
1997
 */
1998
function api_is_in_gradebook()
1999
{
2000
    return Session::read('in_gradebook', false);
2001
}
2002
2003
/**
2004
 * Set that we are in a page inside a gradebook.
2005
 *
2006
 * @return bool
2007
 */
2008
function api_set_in_gradebook()
2009
{
2010
    Session::write('in_gradebook', true);
2011
}
2012
2013
/**
2014
 * Remove gradebook session.
2015
 */
2016
function api_remove_in_gradebook()
2017
{
2018
    Session::erase('in_gradebook');
2019
}
2020
2021
/**
2022
 * Returns the current course info array see api_format_course_array()
2023
 * If the course_code is given, the returned array gives info about that
2024
 * particular course, if none given it gets the course info from the session.
2025
 *
2026
 * @param string $course_code
2027
 * @param bool   $strict
2028
 *
2029
 * @return array
2030
 */
2031
function api_get_course_info($course_code = null, $strict = false)
0 ignored issues
show
Unused Code introduced by
The parameter $strict is not used and could be removed. ( Ignorable by Annotation )

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

2031
function api_get_course_info($course_code = null, /** @scrutinizer ignore-unused */ $strict = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2032
{
2033
    if (!empty($course_code)) {
2034
        $course_code = Database::escape_string($course_code);
2035
        $courseId = api_get_course_int_id($course_code);
2036
2037
        if (empty($courseId)) {
2038
            return [];
2039
        }
2040
2041
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2042
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2043
        $sql = "SELECT
2044
                    course.*,
2045
                    course_category.code faCode,
2046
                    course_category.name faName
2047
                FROM $course_table
2048
                LEFT JOIN $course_cat_table
2049
                ON course.category_code = course_category.code
2050
                WHERE course.id = $courseId";
2051
        $result = Database::query($sql);
2052
        $courseInfo = [];
2053
        if (Database::num_rows($result) > 0) {
2054
            $data = Database::fetch_array($result);
2055
            $courseInfo = api_format_course_array($data);
2056
        }
2057
2058
        return $courseInfo;
2059
    }
2060
2061
    $_course = Session::read('_course');
2062
    if ($_course == '-1') {
2063
        $_course = [];
2064
    }
2065
2066
    return $_course;
2067
}
2068
2069
/**
2070
 * @param int $courseId
2071
 *
2072
 * @return \Chamilo\CoreBundle\Entity\Course
2073
 */
2074
function api_get_course_entity($courseId = 0)
2075
{
2076
    if (empty($courseId)) {
2077
        $courseId = api_get_course_int_id();
2078
    }
2079
2080
    return CourseManager::getManager()->find($courseId);
2081
}
2082
2083
/**
2084
 * @param int $id
2085
 *
2086
 * @return \Chamilo\CoreBundle\Entity\Session
2087
 */
2088
function api_get_session_entity($id = 0)
2089
{
2090
    if (empty($id)) {
2091
        $id = api_get_session_id();
2092
    }
2093
2094
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2095
}
2096
2097
/**
2098
 * Returns the current course info array.
2099
2100
 * Now if the course_code is given, the returned array gives info about that
2101
 * particular course, not specially the current one.
2102
 *
2103
 * @param int $id Numeric ID of the course
2104
 *
2105
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2106
 */
2107
function api_get_course_info_by_id($id = null)
2108
{
2109
    if (!empty($id)) {
2110
        $id = (int) $id;
2111
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2112
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2113
        $sql = "SELECT
2114
                    course.*,
2115
                    course_category.code faCode,
2116
                    course_category.name faName
2117
                FROM $course_table
2118
                LEFT JOIN $course_cat_table
2119
                ON course.category_code = course_category.code
2120
                WHERE course.id = $id";
2121
        $result = Database::query($sql);
2122
        $_course = [];
2123
        if (Database::num_rows($result) > 0) {
2124
            $row = Database::fetch_array($result);
2125
            $_course = api_format_course_array($row);
2126
        }
2127
2128
        return $_course;
2129
    }
2130
2131
    global $_course;
2132
    if ($_course == '-1') {
2133
        $_course = [];
2134
    }
2135
2136
    return $_course;
2137
}
2138
2139
/**
2140
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2141
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
2142
 * now possibly causing massive confusion as a new "id" field has been added to
2143
 * the course table in 1.9.0.
2144
 *
2145
 * @param $course_data
2146
 *
2147
 * @return array
2148
 *
2149
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2150
 */
2151
function api_format_course_array($course_data)
2152
{
2153
    if (empty($course_data)) {
2154
        return [];
2155
    }
2156
2157
    $_course = [];
2158
    $_course['id'] = $course_data['code'];
2159
    $_course['real_id'] = $course_data['id'];
2160
2161
    // Added
2162
    $_course['code'] = $course_data['code'];
2163
    $_course['name'] = $course_data['title'];
2164
    $_course['title'] = $course_data['title'];
2165
    $_course['official_code'] = $course_data['visual_code'];
2166
    $_course['visual_code'] = $course_data['visual_code'];
2167
    $_course['sysCode'] = $course_data['code'];
2168
    $_course['path'] = $course_data['directory']; // Use as key in path.
2169
    $_course['directory'] = $course_data['directory'];
2170
    $_course['creation_date'] = $course_data['creation_date'];
2171
    $_course['titular'] = $course_data['tutor_name'];
2172
    $_course['language'] = $course_data['course_language'];
2173
    $_course['extLink']['url'] = $course_data['department_url'];
2174
    $_course['extLink']['name'] = $course_data['department_name'];
2175
    $_course['categoryCode'] = $course_data['faCode'];
2176
    $_course['categoryName'] = $course_data['faName'];
2177
    $_course['visibility'] = $course_data['visibility'];
2178
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2179
    $_course['subscribe'] = $course_data['subscribe'];
2180
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2181
    $_course['course_language'] = $course_data['course_language'];
2182
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2183
    $_course['legal'] = $course_data['legal'];
2184
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2185
    $_course['department_name'] = $course_data['department_name'];
2186
    $_course['department_url'] = $course_data['department_url'];
2187
2188
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2189
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2190
2191
    // Course password
2192
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2193
    $_course['disk_quota'] = $course_data['disk_quota'];
2194
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2195
2196
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2197
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2198
    }
2199
2200
    // Course image
2201
    $_course['course_image_source'] = '';
2202
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2203
        $url_image = $webCourseHome.'/course-pic85x85.png';
2204
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2205
    } else {
2206
        $url_image = Display::return_icon(
2207
            'course.png',
2208
            null,
2209
            null,
2210
            ICON_SIZE_BIG,
2211
            null,
2212
            true,
2213
            false
2214
        );
2215
    }
2216
    $_course['course_image'] = $url_image;
2217
2218
    // Course large image
2219
    $_course['course_image_large_source'] = '';
2220
    if (file_exists($courseSys.'/course-pic.png')) {
2221
        $url_image = $webCourseHome.'/course-pic.png';
2222
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2223
    } else {
2224
        $url_image = Display::return_icon(
2225
            'session_default.png',
2226
            null,
2227
            null,
2228
            null,
2229
            null,
2230
            true,
2231
            false
2232
        );
2233
    }
2234
    $_course['course_image_large'] = $url_image;
2235
2236
    return $_course;
2237
}
2238
2239
/**
2240
 * Returns a difficult to guess password.
2241
 *
2242
 * @param int $length the length of the password
2243
 *
2244
 * @return string the generated password
2245
 */
2246
function api_generate_password($length = 8)
2247
{
2248
    if ($length < 2) {
2249
        $length = 2;
2250
    }
2251
2252
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2253
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2254
    $minNumbers = 2;
2255
    $length = $length - $minNumbers;
2256
    $minLowerCase = round($length / 2);
2257
    $minUpperCase = $length - $minLowerCase;
2258
2259
    $password = '';
2260
    $passwordRequirements = api_get_configuration_value('password_requirements');
2261
2262
    $factory = new RandomLib\Factory();
2263
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2264
2265
    if (!empty($passwordRequirements)) {
2266
        $length = $passwordRequirements['min']['length'];
2267
        $minNumbers = $passwordRequirements['min']['numeric'];
2268
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2269
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2270
2271
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2272
        // Add the rest to fill the length requirement
2273
        if ($rest > 0) {
2274
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2275
        }
2276
    }
2277
2278
    // Min digits default 2
2279
    for ($i = 0; $i < $minNumbers; $i++) {
2280
        $password .= $generator->generateInt(2, 9);
2281
    }
2282
2283
    // Min lowercase
2284
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2285
2286
    // Min uppercase
2287
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2288
    $password = str_shuffle($password);
2289
2290
    return $password;
2291
}
2292
2293
/**
2294
 * Checks a password to see wether it is OK to use.
2295
 *
2296
 * @param string $password
2297
 *
2298
 * @return bool if the password is acceptable, false otherwise
2299
 *              Notes about what a password "OK to use" is:
2300
 *              1. The password should be at least 5 characters long.
2301
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2302
 *              3. The password should contain at least 3 letters.
2303
 *              4. It should contain at least 2 digits.
2304
 *              Settings will change if the configuration value is set: password_requirements
2305
 */
2306
function api_check_password($password)
2307
{
2308
    $passwordRequirements = Security::getPasswordRequirements();
2309
2310
    $minLength = $passwordRequirements['min']['length'];
2311
    $minNumbers = $passwordRequirements['min']['numeric'];
2312
    // Optional
2313
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2314
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2315
2316
    $minLetters = $minLowerCase + $minUpperCase;
2317
    $passwordLength = api_strlen($password);
2318
2319
    $conditions = [
2320
        'min_length' => $passwordLength >= $minLength,
2321
    ];
2322
2323
    $digits = 0;
2324
    $lowerCase = 0;
2325
    $upperCase = 0;
2326
2327
    for ($i = 0; $i < $passwordLength; $i++) {
2328
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2329
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2330
            $upperCase++;
2331
        }
2332
2333
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2334
            $lowerCase++;
2335
        }
2336
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2337
            $digits++;
2338
        }
2339
    }
2340
2341
    // Min number of digits
2342
    $conditions['min_numeric'] = $digits >= $minNumbers;
2343
2344
    if (!empty($minUpperCase)) {
2345
        // Uppercase
2346
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2347
    }
2348
2349
    if (!empty($minLowerCase)) {
2350
        // Lowercase
2351
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2352
    }
2353
2354
    // Min letters
2355
    $letters = $upperCase + $lowerCase;
2356
    $conditions['min_letters'] = $letters >= $minLetters;
2357
2358
    $isPasswordOk = true;
2359
    foreach ($conditions as $condition) {
2360
        if ($condition === false) {
2361
            $isPasswordOk = false;
2362
            break;
2363
        }
2364
    }
2365
2366
    if ($isPasswordOk === false) {
2367
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2368
        $output .= Security::getPasswordRequirementsToString($conditions);
2369
2370
        Display::addFlash(Display::return_message($output, 'warning', false));
2371
    }
2372
2373
    return $isPasswordOk;
2374
}
2375
2376
/**
2377
 * Clears the user ID from the session if it was the anonymous user. Generally
2378
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2379
 * in the wrong context.
2380
 * This function is to be used in conjunction with the api_set_anonymous()
2381
 * function to simulate the user existence in case of an anonymous visit.
2382
 *
2383
 * @param bool      database check switch - passed to api_is_anonymous()
2384
 *
2385
 * @return bool true if succesfully unregistered, false if not anonymous
2386
 */
2387
function api_clear_anonymous($db_check = false)
2388
{
2389
    global $_user;
2390
    if (api_is_anonymous($_user['user_id'], $db_check)) {
2391
        unset($_user['user_id']);
2392
        Session::erase('_uid');
2393
2394
        return true;
2395
    }
2396
2397
    return false;
2398
}
2399
2400
/**
2401
 * Returns the status string corresponding to the status code.
2402
 *
2403
 * @author Noel Dieschburg
2404
 *
2405
 * @param the int status code
2406
 *
2407
 * @return string
2408
 */
2409
function get_status_from_code($status_code)
2410
{
2411
    switch ($status_code) {
2412
        case STUDENT:
2413
            return get_lang('Student', '');
2414
        case COURSEMANAGER:
2415
            return get_lang('Teacher', '');
2416
        case SESSIONADMIN:
2417
            return get_lang('SessionsAdmin', '');
2418
        case DRH:
2419
            return get_lang('Drh', '');
2420
    }
2421
}
2422
2423
/**
2424
 * Sets the current user as anonymous if it hasn't been identified yet. This
2425
 * function should be used inside a tool only. The function api_clear_anonymous()
2426
 * acts in the opposite direction by clearing the anonymous user's data every
2427
 * time we get on a course homepage or on a neutral page (index, admin, my space).
2428
 *
2429
 * @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2430
 */
2431
function api_set_anonymous()
2432
{
2433
    return false;
2434
2435
    global $_user;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2436
2437
    if (!empty($_user['user_id'])) {
2438
        return false;
2439
    }
2440
2441
    $user_id = api_get_anonymous_id();
2442
    if ($user_id == 0) {
2443
        return false;
2444
    }
2445
2446
    if (isset($_user['is_anonymous'])) {
2447
        return false;
2448
    }
2449
2450
    Session::erase('_user');
2451
    $_user['user_id'] = $user_id;
2452
    $_user['is_anonymous'] = true;
2453
    $GLOBALS['_user'] = $_user;
2454
    Session::write('_user', $_user);
2455
2456
    return true;
2457
}
2458
2459
/**
2460
 * Gets the current Chamilo (not PHP/cookie) session ID.
2461
 *
2462
 * @return int O if no active session, the session ID otherwise
2463
 */
2464
function api_get_session_id()
2465
{
2466
    return (int) Session::read('id_session', 0);
2467
}
2468
2469
/**
2470
 * Gets the current Chamilo (not social network) group ID.
2471
 *
2472
 * @return int O if no active session, the session ID otherwise
2473
 */
2474
function api_get_group_id()
2475
{
2476
    return Session::read('_gid', 0);
2477
}
2478
2479
/**
2480
 * Gets the current or given session name.
2481
 *
2482
 * @param   int     Session ID (optional)
2483
 *
2484
 * @return string The session name, or null if not found
2485
 */
2486
function api_get_session_name($session_id = 0)
2487
{
2488
    if (empty($session_id)) {
2489
        $session_id = api_get_session_id();
2490
        if (empty($session_id)) {
2491
            return null;
2492
        }
2493
    }
2494
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2495
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2496
    $r = Database::query($s);
2497
    $c = Database::num_rows($r);
2498
    if ($c > 0) {
2499
        //technically, there can be only one, but anyway we take the first
2500
        $rec = Database::fetch_array($r);
2501
2502
        return $rec['name'];
2503
    }
2504
2505
    return null;
2506
}
2507
2508
/**
2509
 * Gets the session info by id.
2510
 *
2511
 * @param int $id Session ID
2512
 *
2513
 * @return array information of the session
2514
 */
2515
function api_get_session_info($id)
2516
{
2517
    return SessionManager::fetch($id);
2518
}
2519
2520
/**
2521
 * Gets the session visibility by session id.
2522
 *
2523
 * @param int  $session_id
2524
 * @param int  $courseId
2525
 * @param bool $ignore_visibility_for_admins
2526
 *
2527
 * @return int
2528
 *             0 = session still available,
2529
 *             SESSION_VISIBLE_READ_ONLY = 1,
2530
 *             SESSION_VISIBLE = 2,
2531
 *             SESSION_INVISIBLE = 3
2532
 */
2533
function api_get_session_visibility(
2534
    $session_id,
2535
    $courseId = null,
2536
    $ignore_visibility_for_admins = true
2537
) {
2538
    if (api_is_platform_admin()) {
2539
        if ($ignore_visibility_for_admins) {
2540
            return SESSION_AVAILABLE;
2541
        }
2542
    }
2543
2544
    $now = time();
2545
2546
    if (empty($session_id)) {
2547
        return 0; // Means that the session is still available.
2548
    }
2549
2550
    $session_id = (int) $session_id;
2551
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2552
2553
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2554
2555
    if (Database::num_rows($result) <= 0) {
2556
        return SESSION_INVISIBLE;
2557
    }
2558
2559
    $row = Database::fetch_array($result, 'ASSOC');
2560
    $visibility = $original_visibility = $row['visibility'];
2561
2562
    // I don't care the session visibility.
2563
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2564
        // Session duration per student.
2565
        if (isset($row['duration']) && !empty($row['duration'])) {
2566
            $duration = $row['duration'] * 24 * 60 * 60;
2567
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2568
2569
            // If there is a session duration but there is no previous
2570
            // access by the user, then the session is still available
2571
            if (count($courseAccess) == 0) {
2572
                return SESSION_AVAILABLE;
2573
            }
2574
2575
            $currentTime = time();
2576
            $firstAccess = isset($courseAccess['login_course_date'])
2577
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2578
                : 0;
2579
            $userDurationData = SessionManager::getUserSession(
2580
                api_get_user_id(),
2581
                $session_id
2582
            );
2583
            $userDuration = isset($userDurationData['duration'])
2584
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2585
                : 0;
2586
2587
            $totalDuration = $firstAccess + $duration + $userDuration;
2588
2589
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2590
        }
2591
2592
        return SESSION_AVAILABLE;
2593
    }
2594
2595
    // If start date was set.
2596
    if (!empty($row['access_start_date'])) {
2597
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2598
    }
2599
2600
    // If the end date was set.
2601
    if (!empty($row['access_end_date'])) {
2602
        // Only if date_start said that it was ok
2603
        if ($visibility === SESSION_AVAILABLE) {
2604
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2605
                ? SESSION_AVAILABLE // Date still available
2606
                : $row['visibility']; // Session ends
2607
        }
2608
    }
2609
2610
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2611
    $isCoach = api_is_coach($session_id, $courseId);
2612
2613
    if ($isCoach) {
2614
        // Test start date.
2615
        if (!empty($row['coach_access_start_date'])) {
2616
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2617
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2618
        }
2619
2620
        // Test end date.
2621
        if (!empty($row['coach_access_end_date'])) {
2622
            if ($visibility === SESSION_AVAILABLE) {
2623
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2624
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2625
            }
2626
        }
2627
    }
2628
2629
    return $visibility;
2630
}
2631
2632
/**
2633
 * This function returns a (star) session icon if the session is not null and
2634
 * the user is not a student.
2635
 *
2636
 * @param int $session_id
2637
 * @param int $status_id  User status id - if 5 (student), will return empty
2638
 *
2639
 * @return string Session icon
2640
 */
2641
function api_get_session_image($session_id, $status_id)
2642
{
2643
    $session_id = (int) $session_id;
2644
    $session_img = '';
2645
    if ((int) $status_id != 5) { //check whether is not a student
2646
        if ($session_id > 0) {
2647
            $session_img = "&nbsp;&nbsp;".Display::return_icon(
2648
                'star.png',
2649
                get_lang('SessionSpecificResource'),
2650
                ['align' => 'absmiddle'],
2651
                ICON_SIZE_SMALL
2652
            );
2653
        }
2654
    }
2655
2656
    return $session_img;
2657
}
2658
2659
/**
2660
 * This function add an additional condition according to the session of the course.
2661
 *
2662
 * @param int    $session_id        session id
2663
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2664
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2665
 *                                  false for strict session condition
2666
 * @param string $session_field
2667
 *
2668
 * @return string condition of the session
2669
 */
2670
function api_get_session_condition(
2671
    $session_id,
2672
    $and = true,
2673
    $with_base_content = false,
2674
    $session_field = 'session_id'
2675
) {
2676
    $session_id = (int) $session_id;
2677
2678
    if (empty($session_field)) {
2679
        $session_field = "session_id";
2680
    }
2681
    // Condition to show resources by session
2682
    $condition_add = $and ? " AND " : " WHERE ";
2683
2684
    if ($with_base_content) {
2685
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2686
    } else {
2687
        if (empty($session_id)) {
2688
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2689
        } else {
2690
            $condition_session = $condition_add." $session_field = $session_id ";
2691
        }
2692
    }
2693
2694
    return $condition_session;
2695
}
2696
2697
/**
2698
 * Returns the value of a setting from the web-adjustable admin config settings.
2699
 *
2700
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2701
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2702
 * instead of
2703
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2704
 *
2705
 * @param string $variable The variable name
2706
 *
2707
 * @return string
2708
 */
2709
function api_get_setting($variable)
2710
{
2711
    $settingsManager = Container::getSettingsManager();
2712
    if (empty($settingsManager)) {
2713
        return '';
2714
    }
2715
    $variable = trim($variable);
2716
2717
    switch ($variable) {
2718
        case 'header_extra_content':
2719
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2720
            if (file_exists($filename)) {
2721
                $value = file_get_contents($filename);
2722
2723
                return $value;
2724
            } else {
2725
                return '';
2726
            }
2727
            break;
2728
        case 'footer_extra_content':
2729
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2730
            if (file_exists($filename)) {
2731
                $value = file_get_contents($filename);
2732
2733
                return $value;
2734
            } else {
2735
                return '';
2736
            }
2737
            break;
2738
        case 'server_type':
2739
            $test = ['dev', 'test'];
2740
            $environment = Container::getEnvironment();
2741
            if (in_array($environment, $test)) {
2742
                return 'test';
2743
            }
2744
2745
            return 'prod';
2746
        case 'stylesheets':
2747
            $variable = 'platform.theme';
2748
        // deprecated settings
2749
        // no break
2750
        case 'openid_authentication':
2751
        case 'sso_authentication':
2752
        case 'service_ppt2lp':
2753
        case 'add_cas_login_button_cas_button_label':
2754
        case 'add_cas_login_button_cas_button_comment':
2755
        case 'add_cas_login_button_cas_image_url':
2756
        case 'add_cas_logout_button_cas_logout_label':
2757
        case 'add_cas_logout_button_cas_logout_comment':
2758
        case 'add_cas_logout_button_cas_logout_image_url':
2759
        case 'add_facebook_login_button_facebook_button_url':
2760
        case 'add_shibboleth_login_button_shibboleth_button_label':
2761
        case 'add_shibboleth_login_button_shibboleth_button_comment':
2762
        case 'add_shibboleth_login_button_shibboleth_image_url':
2763
        case 'formLogin_hide_unhide_label':
2764
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
2765
            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...
2766
        case 'tool_visible_by_default_at_creation':
2767
            $values = $settingsManager->getSetting($variable);
2768
            $newResult = [];
2769
            foreach ($values as $parameter) {
2770
                $newResult[$parameter] = 'true';
2771
            }
2772
2773
            return $newResult;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $newResult returns the type array which is incompatible with the documented return type string.
Loading history...
2774
            break;
2775
        default:
2776
            return $settingsManager->getSetting($variable);
2777
            break;
2778
    }
2779
2780
    global $_setting;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2781
    if ($variable == 'header_extra_content') {
2782
        $filename = api_get_home_path().'header_extra_content.txt';
2783
        if (file_exists($filename)) {
2784
            $value = file_get_contents($filename);
2785
2786
            return $value;
2787
        } else {
2788
            return '';
2789
        }
2790
    }
2791
    if ($variable == 'footer_extra_content') {
2792
        $filename = api_get_home_path().'footer_extra_content.txt';
2793
        if (file_exists($filename)) {
2794
            $value = file_get_contents($filename);
2795
2796
            return $value;
2797
        } else {
2798
            return '';
2799
        }
2800
    }
2801
    $value = null;
2802
    if (is_null($key)) {
2803
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
2804
    } else {
2805
        if (isset($_setting[$variable][$key])) {
2806
            $value = $_setting[$variable][$key];
2807
        }
2808
    }
2809
2810
    return $value;
2811
}
2812
2813
/**
2814
 * @param string $variable
2815
 * @param string $option
2816
 *
2817
 * @return bool
2818
 */
2819
function api_get_setting_in_list($variable, $option)
2820
{
2821
    $value = api_get_setting($variable);
2822
2823
    return in_array($option, $value);
2824
}
2825
2826
/**
2827
 * @param string $plugin
2828
 * @param string $variable
2829
 *
2830
 * @return string
2831
 */
2832
function api_get_plugin_setting($plugin, $variable)
2833
{
2834
    $variableName = $plugin.'_'.$variable;
2835
    $params = [
2836
        'category = ? AND subkey = ? AND variable = ?' => [
2837
            'Plugins',
2838
            $plugin,
2839
            $variableName,
2840
        ],
2841
    ];
2842
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2843
    $result = Database::select(
2844
        'selected_value',
2845
        $table,
2846
        ['where' => $params],
2847
        'one'
2848
    );
2849
    if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result 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...
2850
        $result = $result['selected_value'];
2851
2852
        return $result;
2853
    }
2854
2855
    return null;
2856
    /// Old code
2857
2858
    $variableName = $plugin.'_'.$variable;
0 ignored issues
show
Unused Code introduced by
$variableName = $plugin . '_' . $variable is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2859
    $result = api_get_setting($variableName);
2860
2861
    if (isset($result[$plugin])) {
2862
        $value = $result[$plugin];
2863
        if (@unserialize($value) !== false) {
2864
            $value = unserialize($value);
2865
        }
2866
2867
        return $value;
2868
    }
2869
2870
    return null;
2871
}
2872
2873
/**
2874
 * Returns the value of a setting from the web-adjustable admin config settings.
2875
 */
2876
function api_get_settings_params($params)
2877
{
2878
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2879
    $result = Database::select('*', $table, ['where' => $params]);
2880
2881
    return $result;
2882
}
2883
2884
/**
2885
 * @param array $params example: [id = ? => '1']
2886
 *
2887
 * @return array
2888
 */
2889
function api_get_settings_params_simple($params)
2890
{
2891
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2892
    $result = Database::select('*', $table, ['where' => $params], 'one');
2893
2894
    return $result;
2895
}
2896
2897
/**
2898
 * Returns the value of a setting from the web-adjustable admin config settings.
2899
 */
2900
function api_delete_settings_params($params)
2901
{
2902
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2903
    $result = Database::delete($table, $params);
2904
2905
    return $result;
2906
}
2907
2908
/**
2909
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2910
 *
2911
 * @return string Escaped version of $_SERVER['PHP_SELF']
2912
 */
2913
function api_get_self()
2914
{
2915
    return htmlentities($_SERVER['PHP_SELF']);
2916
}
2917
2918
/* USER PERMISSIONS */
2919
2920
/**
2921
 * Checks whether current user is a platform administrator.
2922
 *
2923
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2924
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2925
 *
2926
 * @return bool true if the user has platform admin rights,
2927
 *              false otherwise
2928
 *
2929
 * @see usermanager::is_admin(user_id) for a user-id specific function
2930
 */
2931
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2932
{
2933
    $isAdmin = Session::read('is_platformAdmin');
2934
    if ($isAdmin) {
2935
        return true;
2936
    }
2937
    $user = api_get_user_info();
2938
2939
    return
2940
        isset($user['status']) &&
2941
        (
2942
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
2943
            ($allowDrh && $user['status'] == DRH)
2944
        );
2945
}
2946
2947
/**
2948
 * Checks whether the user given as user id is in the admin table.
2949
 *
2950
 * @param int $user_id If none provided, will use current user
2951
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2952
 *
2953
 * @return bool True if the user is admin, false otherwise
2954
 */
2955
function api_is_platform_admin_by_id($user_id = null, $url = null)
2956
{
2957
    $user_id = (int) $user_id;
2958
    if (empty($user_id)) {
2959
        $user_id = api_get_user_id();
2960
    }
2961
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2962
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2963
    $res = Database::query($sql);
2964
    $is_admin = Database::num_rows($res) === 1;
2965
    if (!$is_admin || !isset($url)) {
2966
        return $is_admin;
2967
    }
2968
    // We get here only if $url is set
2969
    $url = (int) $url;
2970
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2971
    $sql = "SELECT * FROM $url_user_table
2972
            WHERE access_url_id = $url AND user_id = $user_id";
2973
    $res = Database::query($sql);
2974
    $result = Database::num_rows($res) === 1;
2975
2976
    return $result;
2977
}
2978
2979
/**
2980
 * Returns the user's numeric status ID from the users table.
2981
 *
2982
 * @param int $user_id If none provided, will use current user
2983
 *
2984
 * @return int User's status (1 for teacher, 5 for student, etc)
2985
 */
2986
function api_get_user_status($user_id = null)
2987
{
2988
    $user_id = (int) $user_id;
2989
    if (empty($user_id)) {
2990
        $user_id = api_get_user_id();
2991
    }
2992
    $table = Database::get_main_table(TABLE_MAIN_USER);
2993
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
2994
    $result = Database::query($sql);
2995
    $status = null;
2996
    if (Database::num_rows($result)) {
2997
        $row = Database::fetch_array($result);
2998
        $status = $row['status'];
2999
    }
3000
3001
    return $status;
3002
}
3003
3004
/**
3005
 * Checks whether current user is allowed to create courses.
3006
 *
3007
 * @return bool true if the user has course creation rights,
3008
 *              false otherwise
3009
 */
3010
function api_is_allowed_to_create_course()
3011
{
3012
    if (api_is_platform_admin()) {
3013
        return true;
3014
    }
3015
3016
    // Teachers can only create courses
3017
    if (api_is_teacher()) {
3018
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
3019
            return true;
3020
        } else {
3021
            return false;
3022
        }
3023
    }
3024
3025
    return Session::read('is_allowedCreateCourse');
3026
}
3027
3028
/**
3029
 * Checks whether the current user is a course administrator.
3030
 *
3031
 * @return bool True if current user is a course administrator
3032
 */
3033
function api_is_course_admin()
3034
{
3035
    if (api_is_platform_admin()) {
3036
        return true;
3037
    }
3038
3039
    return Session::read('is_courseAdmin');
3040
}
3041
3042
/**
3043
 * Checks whether the current user is a course coach
3044
 * Based on the presence of user in session.id_coach (session general coach).
3045
 *
3046
 * @return bool True if current user is a course coach
3047
 */
3048
function api_is_session_general_coach()
3049
{
3050
    return Session::read('is_session_general_coach');
3051
}
3052
3053
/**
3054
 * Checks whether the current user is a course tutor
3055
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3056
 *
3057
 * @return bool True if current user is a course tutor
3058
 */
3059
function api_is_course_tutor()
3060
{
3061
    return Session::read('is_courseTutor');
3062
}
3063
3064
/**
3065
 * @param int $user_id
3066
 * @param int $courseId
3067
 * @param int $session_id
3068
 *
3069
 * @return bool
3070
 */
3071
function api_is_course_session_coach($user_id, $courseId, $session_id)
3072
{
3073
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3074
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3075
3076
    $user_id = (int) $user_id;
3077
    $session_id = (int) $session_id;
3078
    $courseId = (int) $courseId;
3079
3080
    $sql = "SELECT DISTINCT session.id
3081
            FROM $session_table
3082
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3083
            ON session.id = session_rc_ru.session_id
3084
            WHERE
3085
                session_rc_ru.user_id = '".$user_id."'  AND
3086
                session_rc_ru.c_id = '$courseId' AND
3087
                session_rc_ru.status = 2 AND
3088
                session_rc_ru.session_id = '$session_id'";
3089
    $result = Database::query($sql);
3090
3091
    return Database::num_rows($result) > 0;
3092
}
3093
3094
/**
3095
 * Checks whether the current user is a course or session coach.
3096
 *
3097
 * @param int $session_id
3098
 * @param int $courseId
3099
 * @param bool  Check whether we are in student view and, if we are, return false
3100
 *
3101
 * @return bool True if current user is a course or session coach
3102
 */
3103
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3104
{
3105
    $userId = api_get_user_id();
3106
3107
    if (!empty($session_id)) {
3108
        $session_id = (int) $session_id;
3109
    } else {
3110
        $session_id = api_get_session_id();
3111
    }
3112
3113
    // The student preview was on
3114
    if ($check_student_view && api_is_student_view_active()) {
3115
        return false;
3116
    }
3117
3118
    if (!empty($courseId)) {
3119
        $courseId = (int) $courseId;
3120
    } else {
3121
        $courseId = api_get_course_int_id();
3122
    }
3123
3124
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3125
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3126
    $sessionIsCoach = [];
3127
3128
    if (!empty($courseId)) {
3129
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3130
                FROM $session_table s
3131
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3132
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3133
                WHERE
3134
                    session_rc_ru.c_id = '$courseId' AND
3135
                    session_rc_ru.status = 2 AND
3136
                    session_rc_ru.session_id = '$session_id'";
3137
        $result = Database::query($sql);
3138
        $sessionIsCoach = Database::store_result($result);
3139
    }
3140
3141
    if (!empty($session_id)) {
3142
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3143
                FROM $session_table
3144
                WHERE session.id_coach = $userId AND id = $session_id
3145
                ORDER BY access_start_date, access_end_date, name";
3146
        $result = Database::query($sql);
3147
        if (!empty($sessionIsCoach)) {
3148
            $sessionIsCoach = array_merge(
3149
                $sessionIsCoach,
3150
                Database::store_result($result)
3151
            );
3152
        } else {
3153
            $sessionIsCoach = Database::store_result($result);
3154
        }
3155
    }
3156
3157
    return count($sessionIsCoach) > 0;
3158
}
3159
3160
/**
3161
 * Checks whether the current user is a session administrator.
3162
 *
3163
 * @return bool True if current user is a course administrator
3164
 */
3165
function api_is_session_admin()
3166
{
3167
    $user = api_get_user_info();
3168
3169
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
3170
}
3171
3172
/**
3173
 * Checks whether the current user is a human resources manager.
3174
 *
3175
 * @return bool True if current user is a human resources manager
3176
 */
3177
function api_is_drh()
3178
{
3179
    $user = api_get_user_info();
3180
3181
    return isset($user['status']) && $user['status'] == DRH;
3182
}
3183
3184
/**
3185
 * Checks whether the current user is a student.
3186
 *
3187
 * @return bool True if current user is a human resources manager
3188
 */
3189
function api_is_student()
3190
{
3191
    $user = api_get_user_info();
3192
3193
    return isset($user['status']) && $user['status'] == STUDENT;
3194
}
3195
3196
/**
3197
 * Checks whether the current user has the status 'teacher'.
3198
 *
3199
 * @return bool True if current user is a human resources manager
3200
 */
3201
function api_is_teacher()
3202
{
3203
    $user = api_get_user_info();
3204
3205
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
3206
}
3207
3208
/**
3209
 * Checks whether the current user is a invited user.
3210
 *
3211
 * @return bool
3212
 */
3213
function api_is_invitee()
3214
{
3215
    $user = api_get_user_info();
3216
3217
    return isset($user['status']) && $user['status'] == INVITEE;
3218
}
3219
3220
/**
3221
 * This function checks whether a session is assigned into a category.
3222
 *
3223
 * @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...
3224
 * @param string    - category name
3225
 *
3226
 * @return bool - true if is found, otherwise false
3227
 */
3228
function api_is_session_in_category($session_id, $category_name)
3229
{
3230
    $session_id = (int) $session_id;
3231
    $category_name = Database::escape_string($category_name);
3232
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3233
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3234
3235
    $sql = "SELECT 1
3236
            FROM $tbl_session
3237
            WHERE $session_id IN (
3238
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3239
                WHERE
3240
                  s.session_category_id = sc.id AND
3241
                  sc.name LIKE '%$category_name'
3242
            )";
3243
    $rs = Database::query($sql);
3244
3245
    if (Database::num_rows($rs) > 0) {
3246
        return true;
3247
    } else {
3248
        return false;
3249
    }
3250
}
3251
3252
/**
3253
 * Displays the title of a tool.
3254
 * Normal use: parameter is a string:
3255
 * api_display_tool_title("My Tool").
3256
 *
3257
 * Optionally, there can be a subtitle below
3258
 * the normal title, and / or a supra title above the normal title.
3259
 *
3260
 * e.g. supra title:
3261
 * group
3262
 * GROUP PROPERTIES
3263
 *
3264
 * e.g. subtitle:
3265
 * AGENDA
3266
 * calender & events tool
3267
 *
3268
 * @author Hugues Peeters <[email protected]>
3269
 *
3270
 * @param mixed $title_element - it could either be a string or an array
3271
 *                             containing 'supraTitle', 'mainTitle',
3272
 *                             'subTitle'
3273
 */
3274
function api_display_tool_title($title_element)
3275
{
3276
    if (is_string($title_element)) {
3277
        $tit = $title_element;
3278
        unset($title_element);
3279
        $title_element['mainTitle'] = $tit;
3280
    }
3281
    echo '<h3>';
3282
    if (!empty($title_element['supraTitle'])) {
3283
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3284
    }
3285
    if (!empty($title_element['mainTitle'])) {
3286
        echo $title_element['mainTitle'];
3287
    }
3288
    if (!empty($title_element['subTitle'])) {
3289
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3290
    }
3291
    echo '</h3>';
3292
}
3293
3294
/**
3295
 * Displays options for switching between student view and course manager view.
3296
 *
3297
 * Changes in version 1.2 (Patrick Cool)
3298
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3299
 * is changed explicitly
3300
 *
3301
 * Changes in version 1.1 (Patrick Cool)
3302
 * student view now works correctly in subfolders of the document tool
3303
 * student view works correctly in the new links tool
3304
 *
3305
 * Example code for using this in your tools:
3306
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3307
 * //   display_tool_view_option($isStudentView);
3308
 * //}
3309
 * //and in later sections, use api_is_allowed_to_edit()
3310
 *
3311
 * @author Roan Embrechts
3312
 * @author Patrick Cool
3313
 * @author Julio Montoya, changes added in Chamilo
3314
 *
3315
 * @version 1.2
3316
 *
3317
 * @todo rewrite code so it is easier to understand
3318
 */
3319
function api_display_tool_view_option()
3320
{
3321
    if (api_get_setting('student_view_enabled') != 'true') {
3322
        return '';
3323
    }
3324
3325
    $sourceurl = '';
3326
    $is_framed = false;
3327
    // Exceptions apply for all multi-frames pages
3328
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3329
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3330
        return '';
3331
    }
3332
3333
    // Uncomment to remove student view link from document view page
3334
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3335
        if (empty($_GET['lp_id'])) {
3336
            return '';
3337
        }
3338
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3339
        $sourceurl = str_replace(
3340
            'lp/lp_header.php',
3341
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3342
            $sourceurl
3343
        );
3344
        //showinframes doesn't handle student view anyway...
3345
        //return '';
3346
        $is_framed = true;
3347
    }
3348
3349
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3350
    if (!$is_framed) {
3351
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3352
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3353
        } else {
3354
            $sourceurl = $_SERVER['REQUEST_URI'];
3355
        }
3356
    }
3357
3358
    $output_string = '';
3359
    if (!empty($_SESSION['studentview'])) {
3360
        if ($_SESSION['studentview'] == 'studentview') {
3361
            // We have to remove the isStudentView=true from the $sourceurl
3362
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3363
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3364
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3365
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3366
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3367
            // Switching to teacherview
3368
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3369
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3370
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3371
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3372
        }
3373
    } else {
3374
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3375
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3376
    }
3377
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3378
3379
    return $html;
3380
}
3381
3382
// TODO: This is for the permission section.
3383
/**
3384
 * Function that removes the need to directly use is_courseAdmin global in
3385
 * tool scripts. It returns true or false depending on the user's rights in
3386
 * this particular course.
3387
 * Optionally checking for tutor and coach roles here allows us to use the
3388
 * student_view feature altogether with these roles as well.
3389
 *
3390
 * @param bool  Whether to check if the user has the tutor role
3391
 * @param bool  Whether to check if the user has the coach role
3392
 * @param bool  Whether to check if the user has the session coach role
3393
 * @param bool  check the student view or not
3394
 *
3395
 * @author Roan Embrechts
3396
 * @author Patrick Cool
3397
 * @author Julio Montoya
3398
 *
3399
 * @version 1.1, February 2004
3400
 *
3401
 * @return bool true: the user has the rights to edit, false: he does not
3402
 */
3403
function api_is_allowed_to_edit(
3404
    $tutor = false,
3405
    $coach = false,
3406
    $session_coach = false,
3407
    $check_student_view = true
3408
) {
3409
    // Admins can edit anything.
3410
    if (api_is_platform_admin(false)) {
3411
        //The student preview was on
3412
        if ($check_student_view && api_is_student_view_active()) {
3413
            return false;
3414
        } else {
3415
            return true;
3416
        }
3417
    }
3418
3419
    $sessionId = api_get_session_id();
3420
3421
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3422
        $efv = new ExtraFieldValue('course');
3423
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3424
            api_get_course_int_id(),
3425
            'session_courses_read_only_mode'
3426
        );
3427
3428
        if (!empty($lockExrafieldField['value'])) {
3429
            return false;
3430
        }
3431
    }
3432
3433
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3434
    $session_visibility = api_get_session_visibility($sessionId);
3435
    $is_courseAdmin = api_is_course_admin();
3436
3437
    if (!$is_courseAdmin && $tutor) {
3438
        // If we also want to check if the user is a tutor...
3439
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3440
    }
3441
3442
    if (!$is_courseAdmin && $coach) {
3443
        // If we also want to check if the user is a coach...';
3444
        // Check if session visibility is read only for coaches.
3445
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3446
            $is_allowed_coach_to_edit = false;
3447
        }
3448
3449
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3450
            // Check if coach is allowed to edit a course.
3451
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3452
        }
3453
    }
3454
3455
    if (!$is_courseAdmin && $session_coach) {
3456
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3457
    }
3458
3459
    // Check if the student_view is enabled, and if so, if it is activated.
3460
    if (api_get_setting('student_view_enabled') == 'true') {
3461
        if (!empty($sessionId)) {
3462
            // Check if session visibility is read only for coaches.
3463
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3464
                $is_allowed_coach_to_edit = false;
3465
            }
3466
3467
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3468
                // Check if coach is allowed to edit a course.
3469
                $is_allowed = $is_allowed_coach_to_edit;
3470
            } else {
3471
                $is_allowed = false;
3472
            }
3473
            if ($check_student_view) {
3474
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3475
            }
3476
        } else {
3477
            if ($check_student_view) {
3478
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3479
            } else {
3480
                $is_allowed = $is_courseAdmin;
3481
            }
3482
        }
3483
3484
        return $is_allowed;
3485
    } else {
3486
        return $is_courseAdmin;
3487
    }
3488
}
3489
3490
/**
3491
 * Returns true if user is a course coach of at least one course in session.
3492
 *
3493
 * @param int $sessionId
3494
 *
3495
 * @return bool
3496
 */
3497
function api_is_coach_of_course_in_session($sessionId)
3498
{
3499
    if (api_is_platform_admin()) {
3500
        return true;
3501
    }
3502
3503
    $userId = api_get_user_id();
3504
    $courseList = UserManager::get_courses_list_by_session(
3505
        $userId,
3506
        $sessionId
3507
    );
3508
3509
    // Session visibility.
3510
    $visibility = api_get_session_visibility(
3511
        $sessionId,
3512
        null,
3513
        false
3514
    );
3515
3516
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3517
        // Course Coach session visibility.
3518
        $blockedCourseCount = 0;
3519
        $closedVisibilityList = [
3520
            COURSE_VISIBILITY_CLOSED,
3521
            COURSE_VISIBILITY_HIDDEN,
3522
        ];
3523
3524
        foreach ($courseList as $course) {
3525
            // Checking session visibility
3526
            $sessionCourseVisibility = api_get_session_visibility(
3527
                $sessionId,
3528
                $course['real_id']
3529
            );
3530
3531
            $courseIsVisible = !in_array(
3532
                $course['visibility'],
3533
                $closedVisibilityList
3534
            );
3535
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3536
                $blockedCourseCount++;
3537
            }
3538
        }
3539
3540
        // If all courses are blocked then no show in the list.
3541
        if ($blockedCourseCount === count($courseList)) {
3542
            $visibility = SESSION_INVISIBLE;
3543
        } else {
3544
            $visibility = SESSION_VISIBLE;
3545
        }
3546
    }
3547
3548
    switch ($visibility) {
3549
        case SESSION_VISIBLE_READ_ONLY:
3550
        case SESSION_VISIBLE:
3551
        case SESSION_AVAILABLE:
3552
            return true;
3553
            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...
3554
        case SESSION_INVISIBLE:
3555
            return false;
3556
    }
3557
3558
    return false;
3559
}
3560
3561
/**
3562
 * Checks if a student can edit contents in a session depending
3563
 * on the session visibility.
3564
 *
3565
 * @param bool $tutor Whether to check if the user has the tutor role
3566
 * @param bool $coach Whether to check if the user has the coach role
3567
 *
3568
 * @return bool true: the user has the rights to edit, false: he does not
3569
 */
3570
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3571
{
3572
    if (api_is_allowed_to_edit($tutor, $coach)) {
3573
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3574
        return true;
3575
    } else {
3576
        $sessionId = api_get_session_id();
3577
3578
        if ($sessionId == 0) {
3579
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3580
            return true;
3581
        } else {
3582
            // I'm in a session and I'm a student
3583
            // Get the session visibility
3584
            $session_visibility = api_get_session_visibility($sessionId);
3585
            // if 5 the session is still available
3586
            switch ($session_visibility) {
3587
                case SESSION_VISIBLE_READ_ONLY: // 1
3588
                    return false;
3589
                case SESSION_VISIBLE:           // 2
3590
                    return true;
3591
                case SESSION_INVISIBLE:         // 3
3592
                    return false;
3593
                case SESSION_AVAILABLE:         //5
3594
                    return true;
3595
            }
3596
        }
3597
    }
3598
}
3599
3600
/**
3601
 * Checks whether the user is allowed in a specific tool for a specific action.
3602
 *
3603
 * @param string $tool   the tool we are checking if the user has a certain permission
3604
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3605
 *
3606
 * @return bool
3607
 *
3608
 * @author Patrick Cool <[email protected]>, Ghent University
3609
 * @author Julio Montoya
3610
 *
3611
 * @version 1.0
3612
 */
3613
function api_is_allowed($tool, $action, $task_id = 0)
3614
{
3615
    $_user = api_get_user_info();
3616
    $_course = api_get_course_info();
3617
3618
    if (api_is_course_admin()) {
3619
        return true;
3620
    }
3621
3622
    if (is_array($_course) and count($_course) > 0) {
3623
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3624
3625
        // Getting the permissions of this user.
3626
        if ($task_id == 0) {
3627
            $user_permissions = get_permissions('user', $_user['user_id']);
3628
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3629
        }
3630
3631
        // Getting the permissions of the task.
3632
        if ($task_id != 0) {
3633
            $task_permissions = get_permissions('task', $task_id);
3634
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3635
        }
3636
        //print_r($_SESSION['total_permissions']);
3637
3638
        // Getting the permissions of the groups of the user
3639
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3640
3641
        //foreach($groups_of_user as $group)
3642
        //   $this_group_permissions = get_permissions('group', $group);
3643
3644
        // Getting the permissions of the courseroles of the user
3645
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3646
3647
        // Getting the permissions of the platformroles of the user
3648
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3649
3650
        // Getting the permissions of the roles of the groups of the user
3651
        //foreach($groups_of_user as $group)
3652
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3653
3654
        // Getting the permissions of the platformroles of the groups of the user
3655
        //foreach($groups_of_user as $group)
3656
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3657
    }
3658
3659
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3660
    if (api_get_setting('permissions') == 'limited') {
3661
        if ($action == 'Visibility') {
3662
            $action = 'Edit';
3663
        }
3664
        if ($action == 'Move') {
3665
            $action = 'Edit';
3666
        }
3667
    }
3668
3669
    // The session that contains all the permissions already exists for this course
3670
    // so there is no need to requery everything.
3671
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3672
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3673
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3674
            return true;
3675
        } else {
3676
            return false;
3677
        }
3678
    }
3679
}
3680
3681
/**
3682
 * Tells whether this user is an anonymous user.
3683
 *
3684
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3685
 * @param bool $db_check Whether to check in the database (true) or simply in
3686
 *                       the session (false) to see if the current user is the anonymous user
3687
 *
3688
 * @return bool true if this user is anonymous, false otherwise
3689
 */
3690
function api_is_anonymous($user_id = null, $db_check = false)
3691
{
3692
    if ($db_check) {
3693
        if (!isset($user_id)) {
3694
            $user_id = api_get_user_id();
3695
        }
3696
3697
        $info = api_get_user_info($user_id);
3698
3699
        if ($info['status'] == 6 || $user_id == 0 || empty($info)) {
3700
            return true;
3701
        }
3702
    }
3703
3704
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3705
}
3706
3707
/**
3708
 * Displays message "You are not allowed here..." and exits the entire script.
3709
 *
3710
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3711
 * @param string $message
3712
 * @param int    $responseCode
3713
 */
3714
function api_not_allowed(
3715
    $print_headers = false,
0 ignored issues
show
Unused Code introduced by
The parameter $print_headers is not used and could be removed. ( Ignorable by Annotation )

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

3715
    /** @scrutinizer ignore-unused */ $print_headers = false,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
3716
    $message = null,
3717
    $responseCode = 0
3718
) {
3719
    $debug = api_get_setting('server_type') == 'test';
3720
3721
    // Default code is 403 forbidden
3722
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3723
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3724
3725
    // Create new exception rendered by template:
3726
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3727
3728
    // if error is 404 then the template is:
3729
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3730
    $exception = new Exception($message);
3731
    $request = Container::getRequest();
3732
    $exception = \Symfony\Component\Debug\Exception\FlattenException::create($exception, $responseCode);
3733
    $controller = new \Chamilo\ThemeBundle\Controller\ExceptionController(Container::getTwig(), $debug);
3734
    $response = $controller->showAction($request, $exception);
3735
    $response->send();
3736
    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...
3737
3738
    if (api_get_setting('sso_authentication') === 'true') {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
3739
        global $osso;
3740
        if ($osso) {
3741
            $osso->logout();
3742
        }
3743
    }
3744
3745
    $home_url = api_get_path(WEB_PATH);
3746
    $user_id = api_get_user_id();
3747
    $course = api_get_course_id();
3748
3749
    global $this_section;
3750
3751
    if (CustomPages::enabled() && !isset($user_id)) {
3752
        if (empty($user_id)) {
3753
            // Why the CustomPages::enabled() need to be to set the request_uri
3754
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3755
        }
3756
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3757
    }
3758
3759
    $origin = api_get_origin();
3760
3761
    $msg = null;
3762
    if (isset($message)) {
3763
        $msg = $message;
3764
    } else {
3765
        $msg = Display::return_message(
3766
            get_lang('NotAllowedClickBack').'
3767
            <script>function goBack(){window.history.back();}</script>',
3768
            'error',
3769
            false
3770
        );
3771
        $msg .= '<p class="text-center">
3772
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3773
             </p>';
3774
    }
3775
3776
    $msg = Display::div($msg, ['align' => 'center']);
3777
3778
    $show_headers = 0;
3779
    if ($print_headers && $origin != 'learnpath') {
3780
        $show_headers = 1;
3781
    }
3782
3783
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3784
    $tpl->assign('hide_login_link', 1);
3785
    $tpl->assign('content', $msg);
3786
3787
    if (($user_id != 0 && !api_is_anonymous()) &&
3788
        (!isset($course) || $course == -1) &&
3789
        empty($_GET['cidReq'])
3790
    ) {
3791
        // if the access is not authorized and there is some login information
3792
        // but the cidReq is not found, assume we are missing course data and send the user
3793
        // to the user_portal
3794
        $tpl->display_one_col_template();
3795
        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...
3796
    }
3797
3798
    if (!empty($_SERVER['REQUEST_URI']) &&
3799
        (
3800
            !empty($_GET['cidReq']) ||
3801
            $this_section == SECTION_MYPROFILE ||
3802
            $this_section == SECTION_PLATFORM_ADMIN
3803
        )
3804
    ) {
3805
        $courseCode = api_get_course_id();
3806
        // Only display form and return to the previous URL if there was a course ID included
3807
        if ($user_id != 0 && !api_is_anonymous()) {
3808
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3809
            $tpl->assign('content', $msg);
3810
            $tpl->display_one_col_template();
3811
            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...
3812
        }
3813
3814
        if (!is_null($courseCode)) {
3815
            api_set_firstpage_parameter($courseCode);
3816
        }
3817
3818
        // If the user has no user ID, then his session has expired
3819
        $form = api_get_not_allowed_login_form();
3820
3821
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3822
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3823
3824
        if (!empty($courseCode)) {
3825
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3826
        }
3827
3828
        if (api_is_cas_activated()) {
3829
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
3830
            $content .= Display::div(
3831
                "<br/><a href='".get_cas_direct_URL(api_get_course_id())."'>".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>",
3832
                ['align' => 'center']
3833
            );
3834
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3835
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3836
            $content .= "<div style='display:none;'>";
3837
        }
3838
        $content .= '<div class="well">';
3839
        $content .= $form->returnForm();
3840
        $content .= '</div>';
3841
        if (api_is_cas_activated()) {
3842
            $content .= "</div>";
3843
        }
3844
3845
        if (!empty($courseCode)) {
3846
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3847
                get_lang('ReturnToCourseHomepage').'</a></p>';
3848
        } else {
3849
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3850
                get_lang('BackHome').'</a></p>';
3851
        }
3852
3853
        $tpl->setLoginBodyClass();
3854
        $tpl->assign('content', $content);
3855
        $tpl->display_one_col_template();
3856
        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...
3857
    }
3858
3859
    if ($user_id != 0 && !api_is_anonymous()) {
3860
        $tpl->display_one_col_template();
3861
        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...
3862
    }
3863
3864
    $msg = null;
3865
    // The session is over and we were not in a course,
3866
    // or we try to get directly to a private course without being logged
3867
    $courseId = api_get_course_int_id();
3868
    if (!empty($courseId)) {
3869
        api_set_firstpage_parameter(api_get_course_id());
3870
        $tpl->setLoginBodyClass();
3871
3872
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3873
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
3874
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3875
        $casEnabled = api_is_cas_activated();
3876
        if ($casEnabled) {
3877
            $msg .= Display::return_message(
3878
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
3879
                '',
3880
                false
3881
            );
3882
            $msg .= Display::div("<br/><a href='".get_cas_direct_URL(api_get_course_int_id())."'>".getCASLogoHTML()." ".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>", ['align' => 'center']);
3883
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3884
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3885
            $msg .= "<div style='display:none;'>";
3886
        }
3887
        $form = api_get_not_allowed_login_form();
3888
        $msg .= '<div class="well">';
3889
        $msg .= $form->returnForm();
3890
        $msg .= '</div>';
3891
        if ($casEnabled) {
3892
            $msg .= "</div>";
3893
        }
3894
    } else {
3895
        // we were not in a course, return to home page
3896
        $msg = Display::return_message(
3897
            get_lang('NotAllowed'),
3898
            'error',
3899
            false
3900
        );
3901
3902
        $msg .= '<p class="text-center">
3903
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
3904
                 </p>';
3905
3906
        if (!empty($message)) {
3907
            $msg = $message;
3908
        }
3909
3910
        if (api_is_anonymous()) {
3911
            $form = api_get_not_allowed_login_form();
3912
            $msg .= '<div class="well">';
3913
            $msg .= $form->returnForm();
3914
            $msg .= '</div>';
3915
        }
3916
    }
3917
3918
    $tpl->assign('content', $msg);
3919
    $tpl->display_one_col_template();
3920
    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...
3921
}
3922
3923
/**
3924
 * @return FormValidator
3925
 */
3926
function api_get_not_allowed_login_form()
3927
{
3928
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
3929
    $action = str_replace('&amp;', '&', $action);
3930
    Session::write('redirect_after_not_allow_page', $action);
3931
    $action .= '&redirect_after_not_allow_page=1';
3932
3933
    $form = new FormValidator(
3934
        'formLogin',
3935
        'post',
3936
        $action,
3937
        null,
3938
        ['class' => 'form-stacked']
3939
    );
3940
    $params = [
3941
        'placeholder' => get_lang('UserName'),
3942
        'class' => 'col-md-3',
3943
    ];
3944
    if (api_browser_support('autocapitalize')) {
3945
        $params['autocapitalize'] = 'none';
3946
    }
3947
3948
    $form->addElement(
3949
        'text',
3950
        'login',
3951
        null,
3952
        $params
3953
    );
3954
    $form->addElement(
3955
        'password',
3956
        'password',
3957
        null,
3958
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
3959
    ); //new
3960
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
3961
3962
    return $form;
3963
}
3964
3965
/**
3966
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3967
 *
3968
 * @param $last_post_datetime standard output date in a sql query
3969
 *
3970
 * @return int timestamp
3971
 *
3972
 * @author Toon Van Hoecke <[email protected]>
3973
 *
3974
 * @version October 2003
3975
 * @desc convert sql date to unix timestamp
3976
 */
3977
function convert_sql_date($last_post_datetime)
3978
{
3979
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3980
    list($year, $month, $day) = explode('-', $last_post_date);
3981
    list($hour, $min, $sec) = explode(':', $last_post_time);
3982
3983
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3984
}
3985
3986
/**
3987
 * Gets item visibility from the item_property table.
3988
 *
3989
 * Getting the visibility is done by getting the last updated visibility entry,
3990
 * using the largest session ID found if session 0 and another was found (meaning
3991
 * the only one that is actually from the session, in case there are results from
3992
 * session 0 *AND* session n).
3993
 *
3994
 * @param array     Course properties array (result of api_get_course_info())
3995
 * @param string    Tool (learnpath, document, etc)
3996
 * @param int       The item ID in the given tool
3997
 * @param int       The session ID (optional)
3998
 * @param string $tool
3999
 * @param int    $user_id
4000
 * @param string $type
4001
 *
4002
 * @return int -1 on error, 0 if invisible, 1 if visible
4003
 */
4004
function api_get_item_visibility(
4005
    $_course,
4006
    $tool,
4007
    $id,
4008
    $session = 0,
4009
    $user_id = null,
4010
    $type = null,
4011
    $group_id = null
4012
) {
4013
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4014
        return -1;
4015
    }
4016
4017
    $tool = Database::escape_string($tool);
4018
    $id = (int) $id;
4019
    $session = (int) $session;
4020
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4021
    $course_id = (int) $_course['real_id'];
4022
4023
    $userCondition = '';
4024
    if (!empty($user_id)) {
4025
        $user_id = (int) $user_id;
4026
        $userCondition = " AND to_user_id = $user_id ";
4027
    }
4028
4029
    $typeCondition = '';
4030
    if (!empty($type)) {
4031
        $type = Database::escape_string($type);
4032
        $typeCondition = " AND lastedit_type = '$type' ";
4033
    }
4034
4035
    $groupCondition = '';
4036
    if (!empty($group_id)) {
4037
        $group_id = (int) $group_id;
4038
        $groupCondition = " AND to_group_id = '$group_id' ";
4039
    }
4040
4041
    $sql = "SELECT visibility
4042
            FROM $TABLE_ITEMPROPERTY
4043
            WHERE
4044
                c_id = $course_id AND
4045
                tool = '$tool' AND
4046
                ref = $id AND
4047
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4048
                $userCondition $typeCondition $groupCondition
4049
            ORDER BY session_id DESC, lastedit_date DESC
4050
            LIMIT 1";
4051
4052
    $res = Database::query($sql);
4053
    if ($res === false || Database::num_rows($res) == 0) {
4054
        return -1;
4055
    }
4056
    $row = Database::fetch_array($res);
4057
4058
    return (int) $row['visibility'];
4059
}
4060
4061
/**
4062
 * Delete a row in the c_item_property table.
4063
 *
4064
 * @param array  $courseInfo
4065
 * @param string $tool
4066
 * @param int    $itemId
4067
 * @param int    $userId
4068
 * @param int    $groupId    group.iid
4069
 * @param int    $sessionId
4070
 *
4071
 * @return false|null
4072
 */
4073
function api_item_property_delete(
4074
    $courseInfo,
4075
    $tool,
4076
    $itemId,
4077
    $userId,
4078
    $groupId = 0,
4079
    $sessionId = 0
4080
) {
4081
    if (empty($courseInfo)) {
4082
        return false;
4083
    }
4084
4085
    $courseId = (int) $courseInfo['real_id'];
4086
4087
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4088
        return false;
4089
    }
4090
4091
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4092
    $tool = Database::escape_string($tool);
4093
    $itemId = intval($itemId);
4094
    $userId = intval($userId);
4095
    $groupId = intval($groupId);
4096
    $sessionId = intval($sessionId);
4097
4098
    $groupCondition = " AND to_group_id = $groupId ";
4099
    if (empty($groupId)) {
4100
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4101
    }
4102
4103
    $userCondition = " AND to_user_id = $userId ";
4104
    if (empty($userId)) {
4105
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4106
    }
4107
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4108
    $sql = "DELETE FROM $table
4109
            WHERE
4110
                c_id = $courseId AND
4111
                tool  = '$tool' AND
4112
                ref = $itemId
4113
                $sessionCondition
4114
                $userCondition
4115
                $groupCondition
4116
            ";
4117
4118
    Database::query($sql);
4119
}
4120
4121
/**
4122
 * Updates or adds item properties to the Item_propetry table
4123
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4124
 *
4125
 * @param array  $_course        array with course properties
4126
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4127
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4128
 * @param string $last_edit_type add or update action
4129
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4130
 *                               (2) "delete"
4131
 *                               (3) "visible"
4132
 *                               (4) "invisible"
4133
 * @param int    $user_id        id of the editing/adding user
4134
 * @param array  $groupInfo      must include group.iid/group.od
4135
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4136
 * @param string $start_visible  0000-00-00 00:00:00 format
4137
 * @param string $end_visible    0000-00-00 00:00:00 format
4138
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4139
 *
4140
 * @return bool false if update fails
4141
 *
4142
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4143
 *
4144
 * @version January 2005
4145
 * @desc update the item_properties table (if entry not exists, insert) of the course
4146
 */
4147
function api_item_property_update(
4148
    $_course,
4149
    $tool,
4150
    $item_id,
4151
    $last_edit_type,
4152
    $user_id,
4153
    $groupInfo = [],
4154
    $to_user_id = null,
4155
    $start_visible = '',
4156
    $end_visible = '',
4157
    $session_id = 0
4158
) {
4159
    if (empty($_course)) {
4160
        return false;
4161
    }
4162
4163
    $course_id = $_course['real_id'];
4164
4165
    if (empty($course_id)) {
4166
        return false;
4167
    }
4168
4169
    $to_group_id = 0;
4170
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4171
        $to_group_id = (int) $groupInfo['iid'];
4172
    }
4173
4174
    $em = Database::getManager();
4175
4176
    // Definition of variables.
4177
    $tool = Database::escape_string($tool);
4178
    $item_id = (int) $item_id;
4179
    $lastEditTypeNoFilter = $last_edit_type;
4180
    $last_edit_type = Database::escape_string($last_edit_type);
4181
    $user_id = (int) $user_id;
4182
4183
    $startVisible = "NULL";
4184
    if (!empty($start_visible)) {
4185
        $start_visible = Database::escape_string($start_visible);
4186
        $startVisible = "'$start_visible'";
4187
    }
4188
4189
    $endVisible = "NULL";
4190
    if (!empty($end_visible)) {
4191
        $end_visible = Database::escape_string($end_visible);
4192
        $endVisible = "'$end_visible'";
4193
    }
4194
4195
    $to_filter = '';
4196
    $time = api_get_utc_datetime();
4197
4198
    if (!empty($session_id)) {
4199
        $session_id = (int) $session_id;
4200
    } else {
4201
        $session_id = api_get_session_id();
4202
    }
4203
4204
    // Definition of tables.
4205
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4206
4207
    if ($to_user_id <= 0) {
4208
        $to_user_id = null; // No to_user_id set
4209
    }
4210
4211
    if (!is_null($to_user_id)) {
4212
        // $to_user_id has more priority than $to_group_id
4213
        $to_user_id = (int) $to_user_id;
4214
        $to_field = 'to_user_id';
4215
        $to_value = $to_user_id;
4216
    } else {
4217
        // $to_user_id is not set.
4218
        $to_field = 'to_group_id';
4219
        $to_value = $to_group_id;
4220
    }
4221
4222
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4223
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4224
    $condition_session = " AND session_id = $session_id ";
4225
    if (empty($session_id)) {
4226
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4227
    }
4228
4229
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4230
4231
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4232
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4233
    if (is_null($to_user_id) && is_null($to_group_id)) {
4234
        $to_group_id = 0;
4235
    }
4236
4237
    if (!is_null($to_user_id)) {
4238
        // Set filter to intended user.
4239
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4240
    } else {
4241
        // Set filter to intended group.
4242
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4243
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4244
        }
4245
    }
4246
4247
    // Adding filter if set.
4248
    $filter .= $to_filter;
4249
4250
    // Update if possible
4251
    $set_type = '';
4252
4253
    switch ($lastEditTypeNoFilter) {
4254
        case 'delete':
4255
            // delete = make item only visible for the platform admin.
4256
            $visibility = '2';
4257
            if (!empty($session_id)) {
4258
                // Check whether session id already exist into item_properties for updating visibility or add it.
4259
                $sql = "SELECT session_id FROM $tableItemProperty
4260
                        WHERE
4261
                            c_id = $course_id AND
4262
                            tool = '$tool' AND
4263
                            ref = $item_id AND
4264
                            session_id = $session_id";
4265
                $rs = Database::query($sql);
4266
                if (Database::num_rows($rs) > 0) {
4267
                    $sql = "UPDATE $tableItemProperty
4268
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4269
                                lastedit_date       = '$time',
4270
                                lastedit_user_id    = $user_id,
4271
                                visibility          = $visibility,
4272
                                session_id          = $session_id $set_type
4273
                            WHERE $filter";
4274
                    $result = Database::query($sql);
4275
                } else {
4276
                    $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)
4277
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4278
                    $result = Database::query($sql);
4279
                    $id = Database::insert_id();
4280
                    if ($id) {
4281
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4282
                        Database::query($sql);
4283
                    }
4284
                }
4285
            } else {
4286
                $sql = "UPDATE $tableItemProperty
4287
                        SET
4288
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4289
                            lastedit_date='$time',
4290
                            lastedit_user_id = $user_id,
4291
                            visibility = $visibility $set_type
4292
                        WHERE $filter";
4293
                $result = Database::query($sql);
4294
            }
4295
            break;
4296
        case 'visible': // Change item to visible.
4297
            $visibility = '1';
4298
            if (!empty($session_id)) {
4299
                // Check whether session id already exist into item_properties for updating visibility or add it.
4300
                $sql = "SELECT session_id FROM $tableItemProperty
4301
                        WHERE
4302
                            c_id = $course_id AND
4303
                            tool = '$tool' AND
4304
                            ref = $item_id AND
4305
                            session_id = $session_id";
4306
                $rs = Database::query($sql);
4307
                if (Database::num_rows($rs) > 0) {
4308
                    $sql = "UPDATE $tableItemProperty
4309
                            SET
4310
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4311
                                lastedit_date='$time',
4312
                                lastedit_user_id = $user_id,
4313
                                visibility = $visibility,
4314
                                session_id = $session_id $set_type
4315
                            WHERE $filter";
4316
                    $result = Database::query($sql);
4317
                } else {
4318
                    $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)
4319
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4320
                    $result = Database::query($sql);
4321
                    $id = Database::insert_id();
4322
                    if ($id) {
4323
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4324
                        Database::query($sql);
4325
                    }
4326
                }
4327
            } else {
4328
                $sql = "UPDATE $tableItemProperty
4329
                        SET
4330
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4331
                            lastedit_date='$time',
4332
                            lastedit_user_id = $user_id,
4333
                            visibility = $visibility $set_type
4334
                        WHERE $filter";
4335
                $result = Database::query($sql);
4336
            }
4337
            break;
4338
        case 'invisible': // Change item to invisible.
4339
            $visibility = '0';
4340
            if (!empty($session_id)) {
4341
                // Check whether session id already exist into item_properties for updating visibility or add it
4342
                $sql = "SELECT session_id FROM $tableItemProperty
4343
                        WHERE
4344
                            c_id = $course_id AND
4345
                            tool = '$tool' AND
4346
                            ref = $item_id AND
4347
                            session_id = $session_id";
4348
                $rs = Database::query($sql);
4349
                if (Database::num_rows($rs) > 0) {
4350
                    $sql = "UPDATE $tableItemProperty
4351
                            SET
4352
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4353
                                lastedit_date = '$time',
4354
                                lastedit_user_id = $user_id,
4355
                                visibility = $visibility,
4356
                                session_id = $session_id $set_type
4357
                            WHERE $filter";
4358
                    $result = Database::query($sql);
4359
                } else {
4360
                    $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)
4361
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4362
                    $result = Database::query($sql);
4363
                    $id = Database::insert_id();
4364
                    if ($id) {
4365
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4366
                        Database::query($sql);
4367
                    }
4368
                }
4369
            } else {
4370
                $sql = "UPDATE $tableItemProperty
4371
                        SET
4372
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4373
                            lastedit_date = '$time',
4374
                            lastedit_user_id = $user_id,
4375
                            visibility = $visibility $set_type
4376
                        WHERE $filter";
4377
                $result = Database::query($sql);
4378
            }
4379
            break;
4380
        default: // The item will be added or updated.
4381
            $set_type = ", lastedit_type = '$last_edit_type' ";
4382
            $visibility = '1';
4383
            //$filter .= $to_filter; already added
4384
            $sql = "UPDATE $tableItemProperty
4385
                    SET
4386
                      lastedit_date = '$time',
4387
                      lastedit_user_id = $user_id $set_type
4388
                    WHERE $filter";
4389
            $result = Database::query($sql);
4390
    }
4391
4392
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4393
    if ($result == false || Database::affected_rows($result) == 0) {
4394
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4395
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4396
        $objUser = api_get_user_entity($user_id);
4397
        if (empty($objUser)) {
4398
            // Use anonymous
4399
            $user_id = api_get_anonymous_id();
4400
            $objUser = api_get_user_entity($user_id);
4401
        }
4402
4403
        $objGroup = null;
4404
        if (!empty($to_group_id)) {
4405
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4406
        }
4407
4408
        $objToUser = api_get_user_entity($to_user_id);
4409
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4410
4411
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4412
        $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...
4413
4414
        $cItemProperty = new CItemProperty($objCourse);
4415
        $cItemProperty
4416
            ->setTool($tool)
4417
            ->setRef($item_id)
4418
            ->setInsertDate($objTime)
4419
            ->setInsertUser($objUser)
4420
            ->setLasteditDate($objTime)
4421
            ->setLasteditType($last_edit_type)
4422
            ->setGroup($objGroup)
4423
            ->setToUser($objToUser)
4424
            ->setVisibility($visibility)
4425
            ->setStartVisible($startVisibleDate)
4426
            ->setEndVisible($endVisibleDate)
4427
            ->setSession($objSession);
4428
4429
        $em->persist($cItemProperty);
4430
        $em->flush();
4431
4432
        $id = $cItemProperty->getIid();
4433
4434
        if ($id) {
4435
            $cItemProperty->setId($id);
4436
            $em->merge($cItemProperty);
4437
            $em->flush();
4438
4439
            return false;
4440
        }
4441
    }
4442
4443
    return true;
4444
}
4445
4446
/**
4447
 * Gets item property by tool.
4448
 *
4449
 * @param string    course code
4450
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4451
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4452
 * @param int    $session_id
4453
 * @param string $tool
4454
 * @param string $course_code
4455
 *
4456
 * @return array All fields from c_item_property (all rows found) or empty array
4457
 */
4458
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4459
{
4460
    $course_info = api_get_course_info($course_code);
4461
    $tool = Database::escape_string($tool);
4462
4463
    // Definition of tables.
4464
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4465
    $session_id = (int) $session_id;
4466
    $session_condition = ' AND session_id = '.$session_id;
4467
    if (empty($session_id)) {
4468
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4469
    }
4470
    $course_id = $course_info['real_id'];
4471
4472
    $sql = "SELECT * FROM $item_property_table
4473
            WHERE
4474
                c_id = $course_id AND
4475
                tool = '$tool'
4476
                $session_condition ";
4477
    $rs = Database::query($sql);
4478
    $list = [];
4479
    if (Database::num_rows($rs) > 0) {
4480
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4481
            $list[] = $row;
4482
        }
4483
    }
4484
4485
    return $list;
4486
}
4487
4488
/**
4489
 * Gets item property by tool and user.
4490
 *
4491
 * @param int $userId
4492
 * @param int $tool
4493
 * @param int $courseId
4494
 * @param int $session_id
4495
 *
4496
 * @return array
4497
 */
4498
function api_get_item_property_list_by_tool_by_user(
4499
    $userId,
4500
    $tool,
4501
    $courseId,
4502
    $session_id = 0
4503
) {
4504
    $userId = intval($userId);
4505
    $tool = Database::escape_string($tool);
4506
    $session_id = intval($session_id);
4507
    $courseId = intval($courseId);
4508
4509
    // Definition of tables.
4510
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4511
    $session_condition = ' AND session_id = '.$session_id;
4512
    if (empty($session_id)) {
4513
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4514
    }
4515
    $sql = "SELECT * FROM $item_property_table
4516
            WHERE
4517
                insert_user_id = $userId AND
4518
                c_id = $courseId AND
4519
                tool = '$tool'
4520
                $session_condition ";
4521
4522
    $rs = Database::query($sql);
4523
    $list = [];
4524
    if (Database::num_rows($rs) > 0) {
4525
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4526
            $list[] = $row;
4527
        }
4528
    }
4529
4530
    return $list;
4531
}
4532
4533
/**
4534
 * Gets item property id from tool of a course.
4535
 *
4536
 * @param string $course_code course code
4537
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4538
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4539
 * @param int    $sessionId   Session ID (optional)
4540
 *
4541
 * @return int
4542
 */
4543
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4544
{
4545
    $course_info = api_get_course_info($course_code);
4546
    $tool = Database::escape_string($tool);
4547
    $ref = (int) $ref;
4548
4549
    // Definition of tables.
4550
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4551
    $course_id = $course_info['real_id'];
4552
    $sessionId = (int) $sessionId;
4553
    $sessionCondition = " AND session_id = $sessionId ";
4554
    if (empty($sessionId)) {
4555
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4556
    }
4557
    $sql = "SELECT id FROM $tableItemProperty
4558
            WHERE
4559
                c_id = $course_id AND
4560
                tool = '$tool' AND
4561
                ref = $ref
4562
                $sessionCondition";
4563
    $rs = Database::query($sql);
4564
    $item_property_id = '';
4565
    if (Database::num_rows($rs) > 0) {
4566
        $row = Database::fetch_array($rs);
4567
        $item_property_id = $row['id'];
4568
    }
4569
4570
    return $item_property_id;
4571
}
4572
4573
/**
4574
 * Inserts a record in the track_e_item_property table (No update).
4575
 *
4576
 * @param string $tool
4577
 * @param int    $ref
4578
 * @param string $title
4579
 * @param string $content
4580
 * @param int    $progress
4581
 *
4582
 * @return bool|int
4583
 */
4584
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4585
{
4586
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4587
    $course_id = api_get_course_int_id(); //numeric
4588
    $course_code = api_get_course_id(); //alphanumeric
4589
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4590
    if (!empty($item_property_id)) {
4591
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4592
                course_id           = '$course_id',
4593
                item_property_id    = '$item_property_id',
4594
                title               = '".Database::escape_string($title)."',
4595
                content             = '".Database::escape_string($content)."',
4596
                progress            = '".intval($progress)."',
4597
                lastedit_date       = '".api_get_utc_datetime()."',
4598
                lastedit_user_id    = '".api_get_user_id()."',
4599
                session_id          = '".api_get_session_id()."'";
4600
        $result = Database::query($sql);
4601
        $affected_rows = Database::affected_rows($result);
4602
4603
        return $affected_rows;
4604
    }
4605
4606
    return false;
4607
}
4608
4609
/**
4610
 * @param string $tool
4611
 * @param int    $ref
4612
 *
4613
 * @return array|resource
4614
 */
4615
function api_get_track_item_property_history($tool, $ref)
4616
{
4617
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4618
    $course_id = api_get_course_int_id(); //numeric
4619
    $course_code = api_get_course_id(); //alphanumeric
4620
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4621
    $sql = "SELECT * FROM $tbl_stats_item_property
4622
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4623
            ORDER BY lastedit_date DESC";
4624
    $result = Database::query($sql);
4625
    if ($result === false or $result === null) {
4626
        $result = [];
4627
    } else {
4628
        $result = Database::store_result($result, 'ASSOC');
4629
    }
4630
4631
    return $result;
4632
}
4633
4634
/**
4635
 * Gets item property data from tool of a course id.
4636
 *
4637
 * @param int    $course_id
4638
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4639
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4640
 * @param int    $session_id
4641
 * @param int    $groupId
4642
 *
4643
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4644
 */
4645
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4646
{
4647
    $courseInfo = api_get_course_info_by_id($course_id);
4648
4649
    if (empty($courseInfo)) {
4650
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
4651
    }
4652
4653
    $tool = Database::escape_string($tool);
4654
    $course_id = $courseInfo['real_id'];
4655
    $ref = (int) $ref;
4656
    $session_id = (int) $session_id;
4657
4658
    $sessionCondition = " session_id = $session_id";
4659
    if (empty($session_id)) {
4660
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4661
    }
4662
4663
    // Definition of tables.
4664
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4665
4666
    $sql = "SELECT * FROM $table
4667
            WHERE
4668
                c_id = $course_id AND
4669
                tool = '$tool' AND
4670
                ref = $ref AND
4671
                $sessionCondition ";
4672
4673
    if (!empty($groupId)) {
4674
        $groupId = (int) $groupId;
4675
        $sql .= " AND to_group_id = $groupId ";
4676
    }
4677
4678
    $rs = Database::query($sql);
4679
    $row = [];
4680
    if (Database::num_rows($rs) > 0) {
4681
        $row = Database::fetch_array($rs, 'ASSOC');
4682
    }
4683
4684
    return $row;
4685
}
4686
4687
/**
4688
 * Displays a combo box so the user can select his/her preferred language.
4689
 *
4690
 * @param string The desired name= value for the select
4691
 * @param bool Whether we use the JQuery Chozen library or not
4692
 * (in some cases, like the indexing language picker, it can alter the presentation)
4693
 *
4694
 * @return string
4695
 */
4696
function api_get_languages_combo($name = 'language')
4697
{
4698
    $ret = '';
4699
    $platformLanguage = api_get_setting('platformLanguage');
4700
4701
    // Retrieve a complete list of all the languages.
4702
    $language_list = api_get_languages();
4703
4704
    if (count($language_list) < 2) {
4705
        return $ret;
4706
    }
4707
4708
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4709
    if (isset($_SESSION['user_language_choice'])) {
4710
        $default = $_SESSION['user_language_choice'];
4711
    } else {
4712
        $default = $platformLanguage;
4713
    }
4714
4715
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4716
    foreach ($language_list as $key => $value) {
4717
        if ($key == $default) {
4718
            $selected = ' selected="selected"';
4719
        } else {
4720
            $selected = '';
4721
        }
4722
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4723
    }
4724
    $ret .= '</select>';
4725
4726
    return $ret;
4727
}
4728
4729
/**
4730
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4731
 * The form works with or without javascript.
4732
 *
4733
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4734
 * @param bool $showAsButton
4735
 *
4736
 * @return null|string Display the box directly
4737
 */
4738
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4739
{
4740
    // Retrieve a complete list of all the languages.
4741
    $language_list = api_get_languages();
4742
4743
    if (count($language_list) <= 1 && $hide_if_no_choice) {
4744
        // don't show any form
4745
        return '';
4746
    }
4747
4748
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4749
    if (isset($_SESSION['user_language_choice'])) {
4750
        $user_selected_language = $_SESSION['user_language_choice'];
4751
    }
4752
    if (empty($user_selected_language)) {
4753
        $user_selected_language = api_get_setting('platformLanguage');
4754
    }
4755
4756
    $user_selected_language = 'en';
4757
    $countryCode = languageToCountryIsoCode($user_selected_language);
4758
    $language = api_get_language_from_iso($user_selected_language);
4759
4760
    $url = api_get_self();
4761
    if ($showAsButton) {
4762
        $html = '<div class="btn-group">
4763
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4764
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4765
                '.$language->getOriginalName().'
4766
                <span class="caret">
4767
                </span>
4768
              </button>';
4769
    } else {
4770
        $html = '
4771
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4772
                <span class="flag-icon flag-icon-'.$countryCode.'"></span> 
4773
                '.$language->getOriginalName().'
4774
                <span class="caret"></span>
4775
            </a>
4776
            ';
4777
    }
4778
4779
    $html .= '<ul class="dropdown-menu" role="menu">';
4780
    foreach ($language_list as $iso => $data) {
4781
        $urlLink = $url.'?language='.$data;
4782
        $html .= '<li><a href="'.$urlLink.'">';
4783
        $html .= '<span class="flag-icon flag-icon-'.languageToCountryIsoCode($iso).'"></span> '.$data.'</a></li>';
4784
    }
4785
    $html .= '</ul>';
4786
4787
    if ($showAsButton) {
4788
        $html .= '</div>';
4789
    }
4790
4791
    return $html;
4792
}
4793
4794
/**
4795
 * @param string $languageIsoCode
4796
 *
4797
 * @return string
4798
 */
4799
function languageToCountryIsoCode($languageIsoCode)
4800
{
4801
    // @todo save in DB
4802
    switch ($languageIsoCode) {
4803
        case 'ko':
4804
            $country = 'kr';
4805
            break;
4806
        case 'ja':
4807
            $country = 'jp';
4808
            break;
4809
        case 'ca':
4810
            $country = 'es';
4811
            break;
4812
        case 'gl':
4813
            $country = 'es';
4814
            break;
4815
        case 'ka':
4816
            $country = 'ge';
4817
            break;
4818
        case 'sl':
4819
            $country = 'si';
4820
            break;
4821
        case 'eu':
4822
            $country = 'es';
4823
            break;
4824
        case 'cs':
4825
            $country = 'cz';
4826
            break;
4827
        case 'el':
4828
            $country = 'ae';
4829
            break;
4830
        case 'ar':
4831
            $country = 'ae';
4832
            break;
4833
        case 'en':
4834
            $country = 'gb';
4835
            break;
4836
        case 'he':
4837
            $country = 'il';
4838
            break;
4839
        case 'uk':
4840
            $country = 'ua'; //Ukraine
4841
            break;
4842
        case 'da':
4843
            $country = 'dk';
4844
            break;
4845
        case 'pt-BR':
4846
            $country = 'br';
4847
            break;
4848
        case 'qu':
4849
            $country = 'pe';
4850
            break;
4851
        case 'sv':
4852
            $country = 'se';
4853
            break;
4854
        case 'zh-TW':
4855
        case 'zh':
4856
            $country = 'cn';
4857
            break;
4858
        default:
4859
            $country = $languageIsoCode;
4860
            break;
4861
    }
4862
    $country = strtolower($country);
4863
4864
    return $country;
4865
}
4866
4867
/**
4868
 * Returns a list of all the languages that are made available by the admin.
4869
 *
4870
 * @return array An array with all languages. Structure of the array is
4871
 *               array['name'] = An array with the name of every language
4872
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4873
 */
4874
function api_get_languages()
4875
{
4876
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4877
    $sql = "SELECT * FROM $tbl_language WHERE available='1' 
4878
            ORDER BY original_name ASC";
4879
    $result = Database::query($sql);
4880
    $languages = [];
4881
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4882
        $languages[$row['isocode']] = $row['original_name'];
4883
    }
4884
4885
    return $languages;
4886
}
4887
4888
/**
4889
 * Returns a list of all the languages that are made available by the admin.
4890
 *
4891
 * @return array
4892
 */
4893
function api_get_languages_to_array()
4894
{
4895
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4896
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4897
    $result = Database::query($sql);
4898
    $languages = [];
4899
    while ($row = Database::fetch_array($result)) {
4900
        $languages[$row['dokeos_folder']] = $row['original_name'];
4901
    }
4902
4903
    return $languages;
4904
}
4905
4906
/**
4907
 * Returns the id (the database id) of a language.
4908
 *
4909
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4910
 *
4911
 * @return int id of the language
4912
 */
4913
function api_get_language_id($language)
4914
{
4915
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4916
    if (empty($language)) {
4917
        return null;
4918
    }
4919
    $language = Database::escape_string($language);
4920
    $sql = "SELECT id FROM $tbl_language
4921
            WHERE dokeos_folder = '$language' LIMIT 1";
4922
    $result = Database::query($sql);
4923
    $row = Database::fetch_array($result);
4924
4925
    return $row['id'];
4926
}
4927
4928
/**
4929
 * Gets language of the requested type for the current user. Types are :
4930
 * user_profil_lang : profile language of current user
4931
 * user_select_lang : language selected by user at login
4932
 * course_lang : language of the current course
4933
 * platform_lang : default platform language.
4934
 *
4935
 * @param string $lang_type
4936
 *
4937
 * @return string
4938
 */
4939
function api_get_language_from_type($lang_type)
4940
{
4941
    $return = false;
4942
    switch ($lang_type) {
4943
        case 'platform_lang':
4944
            $temp_lang = api_get_setting('platformLanguage');
4945
            if (!empty($temp_lang)) {
4946
                $return = $temp_lang;
4947
            }
4948
            break;
4949
        case 'user_profil_lang':
4950
            $_user = api_get_user_info();
4951
            if (isset($_user['language']) && !empty($_user['language'])) {
4952
                $return = $_user['language'];
4953
            }
4954
            break;
4955
        case 'user_selected_lang':
4956
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
4957
                $return = $_SESSION['user_language_choice'];
4958
            }
4959
            break;
4960
        case 'course_lang':
4961
            global $_course;
4962
            $cidReq = null;
4963
            if (empty($_course)) {
4964
                // Code modified because the local.inc.php file it's declarated after this work
4965
                // causing the function api_get_course_info() returns a null value
4966
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
4967
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
4968
                if (empty($cidReq) && !empty($cDir)) {
4969
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
4970
                    if ($c) {
4971
                        $cidReq = $c;
4972
                    }
4973
                }
4974
            }
4975
            $_course = api_get_course_info($cidReq);
4976
            if (isset($_course['language']) && !empty($_course['language'])) {
4977
                $return = $_course['language'];
4978
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
4979
                if ($showCourseInUserLanguage == 1) {
4980
                    $userInfo = api_get_user_info();
4981
                    if (isset($userInfo['language'])) {
4982
                        $return = $userInfo['language'];
4983
                    }
4984
                }
4985
            }
4986
            break;
4987
        default:
4988
            $return = false;
4989
            break;
4990
    }
4991
4992
    return $return;
4993
}
4994
4995
/**
4996
 * Get the language information by its id.
4997
 *
4998
 * @param int $languageId
4999
 *
5000
 * @throws Exception
5001
 *
5002
 * @return array
5003
 */
5004
function api_get_language_info($languageId)
5005
{
5006
    $language = Database::getManager()
5007
        ->find('ChamiloCoreBundle:Language', intval($languageId));
5008
5009
    if (!$language) {
5010
        return [];
5011
    }
5012
5013
    return [
5014
        'id' => $language->getId(),
5015
        'original_name' => $language->getOriginalName(),
5016
        'english_name' => $language->getEnglishName(),
5017
        'isocode' => $language->getIsocode(),
5018
        'dokeos_folder' => $language->getDokeosFolder(),
5019
        'available' => $language->getAvailable(),
5020
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
5021
    ];
5022
}
5023
5024
/**
5025
 * @param string $code
5026
 *
5027
 * @return \Chamilo\CoreBundle\Entity\Language
5028
 */
5029
function api_get_language_from_iso($code)
5030
{
5031
    $em = Database::getManager();
5032
    $language = $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
5033
5034
    return $language;
5035
}
5036
5037
/**
5038
 * Returns the name of the visual (CSS) theme to be applied on the current page.
5039
 * The returned name depends on the platform, course or user -wide settings.
5040
 *
5041
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
5042
 */
5043
function api_get_visual_theme()
5044
{
5045
    static $visual_theme;
5046
    if (!isset($visual_theme)) {
5047
        // Get style directly from DB
5048
        $styleFromDatabase = api_get_settings_params_simple(
5049
            [
5050
                'variable = ? AND access_url = ?' => [
5051
                    'stylesheets',
5052
                    api_get_current_access_url_id(),
5053
                ],
5054
            ]
5055
        );
5056
        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...
5057
            $platform_theme = $styleFromDatabase['selected_value'];
5058
        } else {
5059
            $platform_theme = api_get_setting('stylesheets');
5060
        }
5061
5062
        // Platform's theme.
5063
        $visual_theme = $platform_theme;
5064
        if (api_get_setting('user_selected_theme') == 'true') {
5065
            $user_info = api_get_user_info();
5066
            if (isset($user_info['theme'])) {
5067
                $user_theme = $user_info['theme'];
5068
5069
                if (!empty($user_theme)) {
5070
                    $visual_theme = $user_theme;
5071
                    // User's theme.
5072
                }
5073
            }
5074
        }
5075
5076
        $course_id = api_get_course_id();
5077
        if (!empty($course_id)) {
5078
            if (api_get_setting('allow_course_theme') == 'true') {
5079
                $course_theme = api_get_course_setting('course_theme', $course_id);
5080
5081
                if (!empty($course_theme) && $course_theme != -1) {
5082
                    if (!empty($course_theme)) {
5083
                        // Course's theme.
5084
                        $visual_theme = $course_theme;
5085
                    }
5086
                }
5087
5088
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5089
                if ($allow_lp_theme == 1) {
5090
                    global $lp_theme_css, $lp_theme_config;
5091
                    // These variables come from the file lp_controller.php.
5092
                    if (!$lp_theme_config) {
5093
                        if (!empty($lp_theme_css)) {
5094
                            // LP's theme.
5095
                            $visual_theme = $lp_theme_css;
5096
                        }
5097
                    }
5098
                }
5099
            }
5100
        }
5101
5102
        if (empty($visual_theme)) {
5103
            $visual_theme = 'chamilo';
5104
        }
5105
5106
        global $lp_theme_log;
5107
        if ($lp_theme_log) {
5108
            $visual_theme = $platform_theme;
5109
        }
5110
    }
5111
5112
    return $visual_theme;
5113
}
5114
5115
/**
5116
 * Returns a list of CSS themes currently available in the CSS folder
5117
 * The folder must have a default.css file.
5118
 *
5119
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5120
 *
5121
 * @return array list of themes directories from the css folder
5122
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5123
 */
5124
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5125
{
5126
    // This configuration value is set by the vchamilo plugin
5127
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5128
5129
    $readCssFolder = function ($dir) use ($virtualTheme) {
5130
        $finder = new Finder();
5131
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5132
        $list = [];
5133
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5134
        foreach ($themes as $theme) {
5135
            $folder = $theme->getFilename();
5136
            // A theme folder is consider if there's a default.css file
5137
            if (!file_exists($theme->getPathname().'/default.css')) {
5138
                continue;
5139
            }
5140
            $name = ucwords(str_replace('_', ' ', $folder));
5141
            if ($folder == $virtualTheme) {
5142
                continue;
5143
            }
5144
            $list[$folder] = $name;
5145
        }
5146
5147
        return $list;
5148
    };
5149
5150
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5151
    $list = $readCssFolder($dir);
5152
5153
    if (!empty($virtualTheme)) {
5154
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5155
        if ($getOnlyThemeFromVirtualInstance) {
5156
            return $newList;
5157
        }
5158
        $list = $list + $newList;
5159
        asort($list);
5160
    }
5161
5162
    return $list;
5163
}
5164
5165
/**
5166
 * Find the largest sort value in a given user_course_category
5167
 * This function is used when we are moving a course to a different category
5168
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5169
 *
5170
 * @author Patrick Cool <[email protected]>, Ghent University
5171
 *
5172
 * @param int $user_course_category the id of the user_course_category
5173
 * @param int $user_id
5174
 *
5175
 * @return int the value of the highest sort of the user_course_category
5176
 */
5177
function api_max_sort_value($user_course_category, $user_id)
5178
{
5179
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5180
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5181
            WHERE
5182
                user_id='".intval($user_id)."' AND
5183
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5184
                user_course_cat='".intval($user_course_category)."'";
5185
    $result_max = Database::query($sql);
5186
    if (Database::num_rows($result_max) == 1) {
5187
        $row_max = Database::fetch_array($result_max);
5188
5189
        return $row_max['max_sort'];
5190
    }
5191
5192
    return 0;
5193
}
5194
5195
/**
5196
 * Transforms a number of seconds in hh:mm:ss format.
5197
 *
5198
 * @author Julian Prud'homme
5199
 *
5200
 * @param int the number of seconds
5201
 *
5202
 * @return string the formated time
5203
 */
5204
function api_time_to_hms($seconds)
5205
{
5206
    // $seconds = -1 means that we have wrong data in the db.
5207
    if ($seconds == -1) {
5208
        return
5209
            get_lang('Unknown').
5210
            Display::return_icon(
5211
                'info2.gif',
5212
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5213
                ['align' => 'absmiddle', 'hspace' => '3px']
5214
            );
5215
    }
5216
5217
    // How many hours ?
5218
    $hours = floor($seconds / 3600);
5219
5220
    // How many minutes ?
5221
    $min = floor(($seconds - ($hours * 3600)) / 60);
5222
5223
    // How many seconds
5224
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5225
5226
    if ($sec < 10) {
5227
        $sec = "0$sec";
5228
    }
5229
5230
    if ($min < 10) {
5231
        $min = "0$min";
5232
    }
5233
5234
    return "$hours:$min:$sec";
5235
}
5236
5237
/* FILE SYSTEM RELATED FUNCTIONS */
5238
5239
/**
5240
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5241
 * The return value is based on the platform administrator's setting
5242
 * "Administration > Configuration settings > Security > Permissions for new directories".
5243
 *
5244
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5245
 */
5246
function api_get_permissions_for_new_directories()
5247
{
5248
    static $permissions;
5249
    if (!isset($permissions)) {
5250
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5251
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5252
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5253
    }
5254
5255
    return $permissions;
5256
}
5257
5258
/**
5259
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5260
 * The return value is based on the platform administrator's setting
5261
 * "Administration > Configuration settings > Security > Permissions for new files".
5262
 *
5263
 * @return int returns the permissions in the format
5264
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5265
 */
5266
function api_get_permissions_for_new_files()
5267
{
5268
    static $permissions;
5269
    if (!isset($permissions)) {
5270
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5271
        // The default value 0666 is according to that in the platform
5272
        // administration panel after fresh system installation.
5273
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5274
    }
5275
5276
    return $permissions;
5277
}
5278
5279
/**
5280
 * Deletes a file, or a folder and its contents.
5281
 *
5282
 * @author      Aidan Lister <[email protected]>
5283
 *
5284
 * @version     1.0.3
5285
 *
5286
 * @param string $dirname Directory to delete
5287
 * @param       bool     Deletes only the content or not
5288
 * @param bool $strict if one folder/file fails stop the loop
5289
 *
5290
 * @return bool Returns TRUE on success, FALSE on failure
5291
 *
5292
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5293
 *
5294
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5295
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5296
 */
5297
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5298
{
5299
    $res = true;
5300
    // A sanity check.
5301
    if (!file_exists($dirname)) {
5302
        return false;
5303
    }
5304
    $php_errormsg = '';
5305
    // Simple delete for a file.
5306
    if (is_file($dirname) || is_link($dirname)) {
5307
        $res = unlink($dirname);
5308
        if ($res === false) {
5309
            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);
5310
        }
5311
5312
        return $res;
5313
    }
5314
5315
    // Loop through the folder.
5316
    $dir = dir($dirname);
5317
    // A sanity check.
5318
    $is_object_dir = is_object($dir);
5319
    if ($is_object_dir) {
5320
        while (false !== $entry = $dir->read()) {
5321
            // Skip pointers.
5322
            if ($entry == '.' || $entry == '..') {
5323
                continue;
5324
            }
5325
5326
            // Recurse.
5327
            if ($strict) {
5328
                $result = rmdirr("$dirname/$entry");
5329
                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...
5330
                    $res = false;
5331
                    break;
5332
                }
5333
            } else {
5334
                rmdirr("$dirname/$entry");
5335
            }
5336
        }
5337
    }
5338
5339
    // Clean up.
5340
    if ($is_object_dir) {
5341
        $dir->close();
5342
    }
5343
5344
    if ($delete_only_content_in_folder == false) {
5345
        $res = rmdir($dirname);
5346
        if ($res === false) {
5347
            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);
5348
        }
5349
    }
5350
5351
    return $res;
5352
}
5353
5354
// TODO: This function is to be simplified. File access modes to be implemented.
5355
/**
5356
 * function adapted from a php.net comment
5357
 * copy recursively a folder.
5358
 *
5359
 * @param the source folder
5360
 * @param the dest folder
5361
 * @param an array of excluded file_name (without extension)
5362
 * @param copied_files the returned array of copied files
5363
 * @param string $source
5364
 * @param string $dest
5365
 */
5366
function copyr($source, $dest, $exclude = [], $copied_files = [])
5367
{
5368
    if (empty($dest)) {
5369
        return false;
5370
    }
5371
    // Simple copy for a file
5372
    if (is_file($source)) {
5373
        $path_info = pathinfo($source);
5374
        if (!in_array($path_info['filename'], $exclude)) {
5375
            copy($source, $dest);
5376
        }
5377
5378
        return true;
5379
    } elseif (!is_dir($source)) {
5380
        //then source is not a dir nor a file, return
5381
        return false;
5382
    }
5383
5384
    // Make destination directory.
5385
    if (!is_dir($dest)) {
5386
        mkdir($dest, api_get_permissions_for_new_directories());
5387
    }
5388
5389
    // Loop through the folder.
5390
    $dir = dir($source);
5391
    while (false !== $entry = $dir->read()) {
5392
        // Skip pointers
5393
        if ($entry == '.' || $entry == '..') {
5394
            continue;
5395
        }
5396
5397
        // Deep copy directories.
5398
        if ($dest !== "$source/$entry") {
5399
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
0 ignored issues
show
Bug introduced by
It seems like $copied_files can also be of type array; however, parameter $copied_files of copyr() does only seem to accept the, maybe add an additional type check? ( Ignorable by Annotation )

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

5399
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5400
        }
5401
    }
5402
    // Clean up.
5403
    $dir->close();
5404
5405
    return true;
5406
}
5407
5408
/**
5409
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5410
 * Documentation header to be added here.
5411
 *
5412
 * @param string $pathname
5413
 * @param string $base_path_document
5414
 * @param int    $session_id
5415
 *
5416
 * @return mixed True if directory already exists, false if a file already exists at
5417
 *               the destination and null if everything goes according to plan
5418
 */
5419
function copy_folder_course_session(
5420
    $pathname,
5421
    $base_path_document,
5422
    $session_id,
5423
    $course_info,
5424
    $document,
5425
    $source_course_id
5426
) {
5427
    $table = Database::get_course_table(TABLE_DOCUMENT);
5428
    $session_id = intval($session_id);
5429
    $source_course_id = intval($source_course_id);
5430
5431
    // Check whether directory already exists.
5432
    if (is_dir($pathname) || empty($pathname)) {
5433
        return true;
5434
    }
5435
5436
    // Ensure that a file with the same name does not already exist.
5437
    if (is_file($pathname)) {
5438
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5439
5440
        return false;
5441
    }
5442
5443
    $course_id = $course_info['real_id'];
5444
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5445
    $new_pathname = $base_path_document;
5446
    $path = '';
5447
5448
    foreach ($folders as $folder) {
5449
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5450
        $path .= DIRECTORY_SEPARATOR.$folder;
5451
5452
        if (!file_exists($new_pathname)) {
5453
            $path = Database::escape_string($path);
5454
5455
            $sql = "SELECT * FROM $table
5456
                    WHERE
5457
                        c_id = $source_course_id AND
5458
                        path = '$path' AND
5459
                        filetype = 'folder' AND
5460
                        session_id = '$session_id'";
5461
            $rs1 = Database::query($sql);
5462
            $num_rows = Database::num_rows($rs1);
5463
5464
            if ($num_rows == 0) {
5465
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5466
5467
                // Insert new folder with destination session_id.
5468
                $params = [
5469
                    'c_id' => $course_id,
5470
                    'path' => $path,
5471
                    'comment' => $document->comment,
5472
                    'title' => basename($new_pathname),
5473
                    'filetype' => 'folder',
5474
                    'size' => '0',
5475
                    'session_id' => $session_id,
5476
                ];
5477
                $document_id = Database::insert($table, $params);
5478
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type integer|false 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...
5479
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5480
                    Database::query($sql);
5481
5482
                    api_item_property_update(
5483
                        $course_info,
5484
                        TOOL_DOCUMENT,
5485
                        $document_id,
5486
                        'FolderCreated',
5487
                        api_get_user_id(),
5488
                        0,
5489
                        0,
5490
                        null,
5491
                        null,
5492
                        $session_id
5493
                    );
5494
                }
5495
            }
5496
        }
5497
    } // en foreach
5498
}
5499
5500
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5501
/**
5502
 * @param string $path
5503
 */
5504
function api_chmod_R($path, $filemode)
5505
{
5506
    if (!is_dir($path)) {
5507
        return chmod($path, $filemode);
5508
    }
5509
5510
    $handler = opendir($path);
5511
    while ($file = readdir($handler)) {
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5511
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5512
        if ($file != '.' && $file != '..') {
5513
            $fullpath = "$path/$file";
5514
            if (!is_dir($fullpath)) {
5515
                if (!chmod($fullpath, $filemode)) {
5516
                    return false;
5517
                }
5518
            } else {
5519
                if (!api_chmod_R($fullpath, $filemode)) {
5520
                    return false;
5521
                }
5522
            }
5523
        }
5524
    }
5525
5526
    closedir($handler);
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5526
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5527
5528
    return chmod($path, $filemode);
5529
}
5530
5531
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5532
/**
5533
 * Parse info file format. (e.g: file.info).
5534
 *
5535
 * Files should use an ini-like format to specify values.
5536
 * White-space generally doesn't matter, except inside values.
5537
 * e.g.
5538
 *
5539
 * @verbatim
5540
 *   key = value
5541
 *   key = "value"
5542
 *   key = 'value'
5543
 *   key = "multi-line
5544
 *
5545
 *   value"
5546
 *   key = 'multi-line
5547
 *
5548
 *   value'
5549
 *   key
5550
 *   =
5551
 *   'value'
5552
 * @endverbatim
5553
 *
5554
 * Arrays are created using a GET-like syntax:
5555
 *
5556
 * @verbatim
5557
 *   key[] = "numeric array"
5558
 *   key[index] = "associative array"
5559
 *   key[index][] = "nested numeric array"
5560
 *   key[index][index] = "nested associative array"
5561
 * @endverbatim
5562
 *
5563
 * PHP constants are substituted in, but only when used as the entire value:
5564
 *
5565
 * Comments should start with a semi-colon at the beginning of a line.
5566
 *
5567
 * This function is NOT for placing arbitrary module-specific settings. Use
5568
 * variable_get() and variable_set() for that.
5569
 *
5570
 * Information stored in the module.info file:
5571
 * - name: The real name of the module for display purposes.
5572
 * - description: A brief description of the module.
5573
 * - dependencies: An array of shortnames of other modules this module depends on.
5574
 * - package: The name of the package of modules this module belongs to.
5575
 *
5576
 * Example of .info file:
5577
 * <code>
5578
 * @verbatim
5579
 *   name = Forum
5580
 *   description = Enables threaded discussions about general topics.
5581
 *   dependencies[] = taxonomy
5582
 *   dependencies[] = comment
5583
 *   package = Core - optional
5584
 *   version = VERSION
5585
 * @endverbatim
5586
 * </code>
5587
 *
5588
 * @param string $filename
5589
 *                         The file we are parsing. Accepts file with relative or absolute path.
5590
 *
5591
 * @return
5592
 *   The info array
5593
 */
5594
function api_parse_info_file($filename)
5595
{
5596
    $info = [];
5597
5598
    if (!file_exists($filename)) {
5599
        return $info;
5600
    }
5601
5602
    $data = file_get_contents($filename);
5603
    if (preg_match_all('
5604
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5605
        ((?:
5606
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5607
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5608
        )+?)
5609
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5610
        (?:
5611
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5612
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5613
          ([^\r\n]*?)                   # Non-quoted string
5614
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5615
        @msx', $data, $matches, PREG_SET_ORDER)) {
5616
        $key = $value1 = $value2 = $value3 = '';
5617
        foreach ($matches as $match) {
5618
            // Fetch the key and value string.
5619
            $i = 0;
5620
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5621
                $$var = isset($match[++$i]) ? $match[$i] : '';
5622
            }
5623
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5624
5625
            // Parse array syntax.
5626
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5627
            $last = array_pop($keys);
0 ignored issues
show
Bug introduced by
It seems like $keys can also be of type false; however, parameter $array of array_pop() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

5627
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5628
            $parent = &$info;
5629
5630
            // Create nested arrays.
5631
            foreach ($keys as $key) {
5632
                if ($key == '') {
5633
                    $key = count($parent);
5634
                }
5635
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5636
                    $parent[$key] = [];
5637
                }
5638
                $parent = &$parent[$key];
5639
            }
5640
5641
            // Handle PHP constants.
5642
            if (defined($value)) {
5643
                $value = constant($value);
5644
            }
5645
5646
            // Insert actual value.
5647
            if ($last == '') {
5648
                $last = count($parent);
5649
            }
5650
            $parent[$last] = $value;
5651
        }
5652
    }
5653
5654
    return $info;
5655
}
5656
5657
/**
5658
 * Gets Chamilo version from the configuration files.
5659
 *
5660
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5661
 */
5662
function api_get_version()
5663
{
5664
    return (string) api_get_configuration_value('system_version');
5665
}
5666
5667
/**
5668
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5669
 *
5670
 * @return string
5671
 */
5672
function api_get_software_name()
5673
{
5674
    $name = api_get_configuration_value('software_name');
5675
    if (!empty($name)) {
5676
        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...
5677
    } else {
5678
        return 'Chamilo';
5679
    }
5680
}
5681
5682
/**
5683
 * Checks whether status given in parameter exists in the platform.
5684
 *
5685
 * @param mixed the status (can be either int either string)
5686
 *
5687
 * @return bool if the status exists, else returns false
5688
 */
5689
function api_status_exists($status_asked)
5690
{
5691
    global $_status_list;
5692
5693
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5694
}
5695
5696
/**
5697
 * Checks whether status given in parameter exists in the platform. The function
5698
 * returns the status ID or false if it does not exist, but given the fact there
5699
 * is no "0" status, the return value can be checked against
5700
 * if(api_status_key()) to know if it exists.
5701
 *
5702
 * @param   mixed   The status (can be either int or string)
5703
 *
5704
 * @return mixed Status ID if exists, false otherwise
5705
 */
5706
function api_status_key($status)
5707
{
5708
    global $_status_list;
5709
5710
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5711
}
5712
5713
/**
5714
 * Gets the status langvars list.
5715
 *
5716
 * @return string[] the list of status with their translations
5717
 */
5718
function api_get_status_langvars()
5719
{
5720
    return [
5721
        COURSEMANAGER => get_lang('Teacher', ''),
5722
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5723
        DRH => get_lang('Drh', ''),
5724
        STUDENT => get_lang('Student', ''),
5725
        ANONYMOUS => get_lang('Anonymous', ''),
5726
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5727
        INVITEE => get_lang('Invited'),
5728
    ];
5729
}
5730
5731
/**
5732
 * The function that retrieves all the possible settings for a certain config setting.
5733
 *
5734
 * @author Patrick Cool <[email protected]>, Ghent University
5735
 */
5736
function api_get_settings_options($var)
5737
{
5738
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5739
    $var = Database::escape_string($var);
5740
    $sql = "SELECT * FROM $table_settings_options
5741
            WHERE variable = '$var'
5742
            ORDER BY id";
5743
    $result = Database::query($sql);
5744
    $settings_options_array = [];
5745
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5746
        $settings_options_array[] = $row;
5747
    }
5748
5749
    return $settings_options_array;
5750
}
5751
5752
/**
5753
 * @param array $params
5754
 */
5755
function api_set_setting_option($params)
5756
{
5757
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5758
    if (empty($params['id'])) {
5759
        Database::insert($table, $params);
5760
    } else {
5761
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5762
    }
5763
}
5764
5765
/**
5766
 * @param array $params
5767
 */
5768
function api_set_setting_simple($params)
5769
{
5770
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5771
    $url_id = api_get_current_access_url_id();
5772
5773
    if (empty($params['id'])) {
5774
        $params['access_url'] = $url_id;
5775
        Database::insert($table, $params);
5776
    } else {
5777
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5778
    }
5779
}
5780
5781
/**
5782
 * @param int $id
5783
 */
5784
function api_delete_setting_option($id)
5785
{
5786
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5787
    if (!empty($id)) {
5788
        Database::delete($table, ['id = ? ' => $id]);
5789
    }
5790
}
5791
5792
/**
5793
 * Sets a platform configuration setting to a given value.
5794
 *
5795
 * @param string    The variable we want to update
5796
 * @param string    The value we want to record
5797
 * @param string    The sub-variable if any (in most cases, this will remain null)
5798
 * @param string    The category if any (in most cases, this will remain null)
5799
 * @param int       The access_url for which this parameter is valid
5800
 * @param string $cat
5801
 *
5802
 * @return bool|null
5803
 */
5804
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5805
{
5806
    if (empty($var)) {
5807
        return false;
5808
    }
5809
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5810
    $var = Database::escape_string($var);
5811
    $value = Database::escape_string($value);
5812
    $access_url = (int) $access_url;
5813
    if (empty($access_url)) {
5814
        $access_url = 1;
5815
    }
5816
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5817
    if (!empty($subvar)) {
5818
        $subvar = Database::escape_string($subvar);
5819
        $select .= " AND subkey = '$subvar'";
5820
    }
5821
    if (!empty($cat)) {
5822
        $cat = Database::escape_string($cat);
5823
        $select .= " AND category = '$cat'";
5824
    }
5825
    if ($access_url > 1) {
5826
        $select .= " AND access_url = $access_url";
5827
    } else {
5828
        $select .= " AND access_url = 1 ";
5829
    }
5830
5831
    $res = Database::query($select);
5832
    if (Database::num_rows($res) > 0) {
5833
        // Found item for this access_url.
5834
        $row = Database::fetch_array($res);
5835
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5836
                WHERE id = ".$row['id'];
5837
        Database::query($sql);
5838
    } else {
5839
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5840
        $select = "SELECT * FROM $t_settings
5841
                   WHERE variable = '$var' AND access_url = 1 ";
5842
        // Just in case
5843
        if ($access_url == 1) {
5844
            if (!empty($subvar)) {
5845
                $select .= " AND subkey = '$subvar'";
5846
            }
5847
            if (!empty($cat)) {
5848
                $select .= " AND category = '$cat'";
5849
            }
5850
            $res = Database::query($select);
5851
            if (Database::num_rows($res) > 0) {
5852
                // We have a setting for access_url 1, but none for the current one, so create one.
5853
                $row = Database::fetch_array($res);
5854
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5855
                        VALUES
5856
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5857
                    "'".$row['type']."','".$row['category']."',".
5858
                    "'$value','".$row['title']."',".
5859
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5860
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5861
                Database::query($insert);
5862
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
5863
                // Such a setting does not exist.
5864
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5865
            }
5866
        } else {
5867
            // Other access url.
5868
            if (!empty($subvar)) {
5869
                $select .= " AND subkey = '$subvar'";
5870
            }
5871
            if (!empty($cat)) {
5872
                $select .= " AND category = '$cat'";
5873
            }
5874
            $res = Database::query($select);
5875
5876
            if (Database::num_rows($res) > 0) {
5877
                // We have a setting for access_url 1, but none for the current one, so create one.
5878
                $row = Database::fetch_array($res);
5879
                if ($row['access_url_changeable'] == 1) {
5880
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5881
                            ('".$row['variable']."',".
5882
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5883
                        "'".$row['type']."','".$row['category']."',".
5884
                        "'$value','".$row['title']."',".
5885
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5886
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5887
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5888
                    Database::query($insert);
5889
                }
5890
            } else { // Such a setting does not exist.
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
5891
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5892
            }
5893
        }
5894
    }
5895
}
5896
5897
/**
5898
 * Sets a whole category of settings to one specific value.
5899
 *
5900
 * @param string    Category
5901
 * @param string    Value
5902
 * @param int       Access URL. Optional. Defaults to 1
5903
 * @param array     Optional array of filters on field type
5904
 * @param string $category
5905
 * @param string $value
5906
 *
5907
 * @return bool
5908
 */
5909
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5910
{
5911
    if (empty($category)) {
5912
        return false;
5913
    }
5914
    $category = Database::escape_string($category);
5915
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5916
    $access_url = (int) $access_url;
5917
    if (empty($access_url)) {
5918
        $access_url = 1;
5919
    }
5920
    if (isset($value)) {
5921
        $value = Database::escape_string($value);
5922
        $sql = "UPDATE $t_s SET selected_value = '$value'
5923
                WHERE category = '$category' AND access_url = $access_url";
5924
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5925
            $sql .= " AND ( ";
5926
            $i = 0;
5927
            foreach ($fieldtype as $type) {
5928
                if ($i > 0) {
5929
                    $sql .= ' OR ';
5930
                }
5931
                $type = Database::escape_string($type);
5932
                $sql .= " type='".$type."' ";
5933
                $i++;
5934
            }
5935
            $sql .= ")";
5936
        }
5937
        $res = Database::query($sql);
5938
5939
        return $res !== false;
5940
    } else {
5941
        $sql = "UPDATE $t_s SET selected_value = NULL
5942
                WHERE category = '$category' AND access_url = $access_url";
5943
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5944
            $sql .= " AND ( ";
5945
            $i = 0;
5946
            foreach ($fieldtype as $type) {
5947
                if ($i > 0) {
5948
                    $sql .= ' OR ';
5949
                }
5950
                $type = Database::escape_string($type);
5951
                $sql .= " type='".$type."' ";
5952
                $i++;
5953
            }
5954
            $sql .= ")";
5955
        }
5956
        $res = Database::query($sql);
5957
5958
        return $res !== false;
5959
    }
5960
}
5961
5962
/**
5963
 * Gets all available access urls in an array (as in the database).
5964
 *
5965
 * @return array An array of database records
5966
 */
5967
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5968
{
5969
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5970
    $from = (int) $from;
5971
    $to = (int) $to;
5972
    $order = Database::escape_string($order, null, false);
5973
    $direction = Database::escape_string($direction, null, false);
5974
    $sql = "SELECT id, url, description, active, created_by, tms
5975
            FROM $table
5976
            ORDER BY $order $direction
5977
            LIMIT $to OFFSET $from";
5978
    $res = Database::query($sql);
5979
5980
    return Database::store_result($res);
5981
}
5982
5983
/**
5984
 * Gets the access url info in an array.
5985
 *
5986
 * @param int  $id            Id of the access url
5987
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5988
 *
5989
 * @return array All the info (url, description, active, created_by, tms)
5990
 *               from the access_url table
5991
 *
5992
 * @author Julio Montoya
5993
 */
5994
function api_get_access_url($id, $returnDefault = true)
5995
{
5996
    static $staticResult;
5997
    $id = (int) $id;
5998
5999
    if (isset($staticResult[$id])) {
6000
        $result = $staticResult[$id];
6001
    } else {
6002
        // Calling the Database:: library dont work this is handmade.
6003
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6004
        $sql = "SELECT url, description, active, created_by, tms
6005
                FROM $table_access_url WHERE id = '$id' ";
6006
        $res = Database::query($sql);
6007
        $result = @Database::fetch_array($res);
6008
        $staticResult[$id] = $result;
6009
    }
6010
6011
    // If the result url is 'http://localhost/' (the default) and the root_web
6012
    // (=current url) is different, and the $id is = 1 (which might mean
6013
    // api_get_current_access_url_id() returned 1 by default), then return the
6014
    // root_web setting instead of the current URL
6015
    // This is provided as an option to avoid breaking the storage of URL-specific
6016
    // homepages in home/localhost/
6017
    if ($id === 1 && $returnDefault === false) {
6018
        $currentUrl = api_get_current_access_url_id();
6019
        // only do this if we are on the main URL (=1), otherwise we could get
6020
        // information on another URL instead of the one asked as parameter
6021
        if ($currentUrl === 1) {
6022
            $rootWeb = api_get_path(WEB_PATH);
6023
            $default = 'http://localhost/';
6024
            if ($result['url'] === $default && $rootWeb != $default) {
6025
                $result['url'] = $rootWeb;
6026
            }
6027
        }
6028
    }
6029
6030
    return $result;
6031
}
6032
6033
/**
6034
 * Gets all the current settings for a specific access url.
6035
 *
6036
 * @param string    The category, if any, that we want to get
6037
 * @param string    Whether we want a simple list (display a category) or
6038
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
6039
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
6040
 *
6041
 * @return array Array of database results for the current settings of the current access URL
6042
 */
6043
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
6044
{
6045
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6046
    $access_url = (int) $access_url;
6047
    $where_condition = '';
6048
    if ($url_changeable == 1) {
6049
        $where_condition = " AND access_url_changeable= '1' ";
6050
    }
6051
    if (empty($access_url) || $access_url == -1) {
6052
        $access_url = 1;
6053
    }
6054
    $sql = "SELECT * FROM $table
6055
            WHERE access_url = $access_url  $where_condition ";
6056
6057
    if (!empty($cat)) {
6058
        $cat = Database::escape_string($cat);
6059
        $sql .= " AND category='$cat' ";
6060
    }
6061
    if ($ordering == 'group') {
6062
        $sql .= " ORDER BY id ASC";
6063
    } else {
6064
        $sql .= " ORDER BY 1,2 ASC";
6065
    }
6066
    $result = Database::query($sql);
6067
    if ($result === null) {
6068
        return [];
6069
    }
6070
    $result = Database::store_result($result, 'ASSOC');
6071
6072
    return $result;
6073
}
6074
6075
/**
6076
 * @param string $value       The value we want to record
6077
 * @param string $variable    The variable name we want to insert
6078
 * @param string $subKey      The subkey for the variable we want to insert
6079
 * @param string $type        The type for the variable we want to insert
6080
 * @param string $category    The category for the variable we want to insert
6081
 * @param string $title       The title
6082
 * @param string $comment     The comment
6083
 * @param string $scope       The scope
6084
 * @param string $subKeyText  The subkey text
6085
 * @param int    $accessUrlId The access_url for which this parameter is valid
6086
 * @param int    $visibility  The changeability of this setting for non-master urls
6087
 *
6088
 * @return int The setting ID
6089
 */
6090
function api_add_setting(
6091
    $value,
6092
    $variable,
6093
    $subKey = '',
6094
    $type = 'textfield',
6095
    $category = '',
6096
    $title = '',
6097
    $comment = '',
6098
    $scope = '',
6099
    $subKeyText = '',
6100
    $accessUrlId = 1,
6101
    $visibility = 0
6102
) {
6103
    $em = Database::getManager();
6104
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6105
    $accessUrlId = (int) $accessUrlId ?: 1;
6106
6107
    if (is_array($value)) {
6108
        $value = serialize($value);
6109
    } else {
6110
        $value = trim($value);
6111
    }
6112
6113
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
6114
6115
    if (!empty($subKey)) {
6116
        $criteria['subkey'] = $subKey;
6117
    }
6118
6119
    // Check if this variable doesn't exist already
6120
    /** @var SettingsCurrent $setting */
6121
    $setting = $settingRepo->findOneBy($criteria);
6122
6123
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true. If $setting can have other possible types, add them to main/inc/lib/api.lib.php:6120
Loading history...
6124
        $setting->setSelectedValue($value);
6125
6126
        $em->persist($setting);
6127
        $em->flush();
6128
6129
        return $setting->getId();
6130
    }
6131
6132
    // Item not found for this access_url, we have to check if the whole thing is missing
6133
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6134
    $setting = new SettingsCurrent();
6135
    $setting
6136
        ->setVariable($variable)
6137
        ->setSelectedValue($value)
6138
        ->setType($type)
6139
        ->setCategory($category)
6140
        ->setSubkey($subKey)
6141
        ->setTitle($title)
6142
        ->setComment($comment)
6143
        ->setScope($scope)
6144
        ->setSubkeytext($subKeyText)
6145
        ->setAccessUrl($accessUrlId)
6146
        ->setAccessUrlChangeable($visibility);
6147
6148
    $em->persist($setting);
6149
    $em->flush();
6150
6151
    return $setting->getId();
6152
}
6153
6154
/**
6155
 * Checks wether a user can or can't view the contents of a course.
6156
 *
6157
 * @deprecated use CourseManager::is_user_subscribed_in_course
6158
 *
6159
 * @param int $userid User id or NULL to get it from $_SESSION
6160
 * @param int $cid    course id to check whether the user is allowed
6161
 *
6162
 * @return bool
6163
 */
6164
function api_is_course_visible_for_user($userid = null, $cid = null)
6165
{
6166
    if ($userid === null) {
6167
        $userid = api_get_user_id();
6168
    }
6169
    if (empty($userid) || strval(intval($userid)) != $userid) {
6170
        if (api_is_anonymous()) {
6171
            $userid = api_get_anonymous_id();
6172
        } else {
6173
            return false;
6174
        }
6175
    }
6176
    $cid = Database::escape_string($cid);
6177
6178
    $courseInfo = api_get_course_info($cid);
6179
    $courseId = $courseInfo['real_id'];
6180
    $is_platformAdmin = api_is_platform_admin();
6181
6182
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6183
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6184
6185
    $sql = "SELECT
6186
                $course_table.category_code,
6187
                $course_table.visibility,
6188
                $course_table.code,
6189
                $course_cat_table.code
6190
            FROM $course_table
6191
            LEFT JOIN $course_cat_table
6192
                ON $course_table.category_code = $course_cat_table.code
6193
            WHERE
6194
                $course_table.code = '$cid'
6195
            LIMIT 1";
6196
6197
    $result = Database::query($sql);
6198
6199
    if (Database::num_rows($result) > 0) {
6200
        $visibility = Database::fetch_array($result);
6201
        $visibility = $visibility['visibility'];
6202
    } else {
6203
        $visibility = 0;
6204
    }
6205
    // Shortcut permissions in case the visibility is "open to the world".
6206
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
6207
        return true;
6208
    }
6209
6210
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6211
6212
    $sql = "SELECT
6213
                is_tutor, status
6214
            FROM $tbl_course_user
6215
            WHERE
6216
                user_id  = '$userid' AND
6217
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6218
                c_id = $courseId
6219
            LIMIT 1";
6220
6221
    $result = Database::query($sql);
6222
6223
    if (Database::num_rows($result) > 0) {
6224
        // This user has got a recorded state for this course.
6225
        $cuData = Database::fetch_array($result);
6226
        $is_courseMember = true;
6227
        $is_courseAdmin = ($cuData['status'] == 1);
6228
    }
6229
6230
    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...
6231
        // This user has no status related to this course.
6232
        // Is it the session coach or the session admin?
6233
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6234
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6235
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6236
6237
        $sql = "SELECT
6238
                    session.id_coach, session_admin_id, session.id
6239
                FROM
6240
                    $tbl_session as session
6241
                INNER JOIN $tbl_session_course
6242
                    ON session_rel_course.session_id = session.id
6243
                    AND session_rel_course.c_id = '$courseId'
6244
                LIMIT 1";
6245
6246
        $result = Database::query($sql);
6247
        $row = Database::store_result($result);
6248
6249
        if ($row[0]['id_coach'] == $userid) {
6250
            $is_courseMember = true;
6251
            $is_courseAdmin = false;
6252
        } elseif ($row[0]['session_admin_id'] == $userid) {
6253
            $is_courseMember = false;
6254
            $is_courseAdmin = false;
6255
        } else {
6256
            // Check if the current user is the course coach.
6257
            $sql = "SELECT 1
6258
                    FROM $tbl_session_course
6259
                    WHERE session_rel_course.c_id = '$courseId'
6260
                    AND session_rel_course.id_coach = '$userid'
6261
                    LIMIT 1";
6262
6263
            $result = Database::query($sql);
6264
6265
            //if ($row = Database::fetch_array($result)) {
6266
            if (Database::num_rows($result) > 0) {
6267
                $is_courseMember = true;
6268
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6269
6270
                $sql = "SELECT status FROM $tbl_user
6271
                        WHERE user_id = $userid
6272
                        LIMIT 1";
6273
6274
                $result = Database::query($sql);
6275
6276
                if (Database::result($result, 0, 0) == 1) {
6277
                    $is_courseAdmin = true;
6278
                } else {
6279
                    $is_courseAdmin = false;
6280
                }
6281
            } else {
6282
                // Check if the user is a student is this session.
6283
                $sql = "SELECT  id
6284
                        FROM $tbl_session_course_user
6285
                        WHERE
6286
                            user_id  = '$userid' AND
6287
                            c_id = '$courseId'
6288
                        LIMIT 1";
6289
6290
                if (Database::num_rows($result) > 0) {
6291
                    // This user haa got a recorded state for this course.
6292
                    while ($row = Database::fetch_array($result)) {
6293
                        $is_courseMember = true;
6294
                        $is_courseAdmin = false;
6295
                    }
6296
                }
6297
            }
6298
        }
6299
    }
6300
6301
    switch ($visibility) {
6302
        case COURSE_VISIBILITY_OPEN_WORLD:
6303
            return true;
6304
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6305
            return isset($userid);
6306
        case COURSE_VISIBILITY_REGISTERED:
6307
        case COURSE_VISIBILITY_CLOSED:
6308
            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...
6309
        case COURSE_VISIBILITY_HIDDEN:
6310
            return $is_platformAdmin;
6311
    }
6312
6313
    return false;
6314
}
6315
6316
/**
6317
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6318
 *
6319
 * @param string the tool of the element
6320
 * @param int the element id in database
6321
 * @param int the session_id to compare with element session id
6322
 * @param string $tool
6323
 *
6324
 * @return bool true if the element is in the session, false else
6325
 */
6326
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6327
{
6328
    if (is_null($session_id)) {
6329
        $session_id = api_get_session_id();
6330
    }
6331
6332
    // Get information to build query depending of the tool.
6333
    switch ($tool) {
6334
        case TOOL_SURVEY:
6335
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6336
            $key_field = 'survey_id';
6337
            break;
6338
        case TOOL_ANNOUNCEMENT:
6339
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6340
            $key_field = 'id';
6341
            break;
6342
        case TOOL_AGENDA:
6343
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6344
            $key_field = 'id';
6345
            break;
6346
        case TOOL_GROUP:
6347
            $table_tool = Database::get_course_table(TABLE_GROUP);
6348
            $key_field = 'id';
6349
            break;
6350
        default:
6351
            return false;
6352
    }
6353
    $course_id = api_get_course_int_id();
6354
6355
    $sql = "SELECT session_id FROM $table_tool 
6356
            WHERE c_id = $course_id AND $key_field =  ".intval($element_id);
6357
    $rs = Database::query($sql);
6358
    if ($element_session_id = Database::result($rs, 0, 0)) {
6359
        if ($element_session_id == intval($session_id)) {
6360
            // The element belongs to the session.
6361
            return true;
6362
        }
6363
    }
6364
6365
    return false;
6366
}
6367
6368
/**
6369
 * Replaces "forbidden" characters in a filename string.
6370
 *
6371
 * @param string $filename
6372
 * @param bool   $treat_spaces_as_hyphens
6373
 *
6374
 * @return string
6375
 */
6376
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6377
{
6378
    // Some non-properly encoded file names can cause the whole file to be
6379
    // skipped when uploaded. Avoid this by detecting the encoding and
6380
    // converting to UTF-8, setting the source as ASCII (a reasonably
6381
    // limited characters set) if nothing could be found (BT#
6382
    $encoding = api_detect_encoding($filename);
6383
    if (empty($encoding)) {
6384
        $encoding = 'ASCII';
6385
    }
6386
    $filename = api_to_system_encoding($filename, $encoding);
6387
    $url = URLify::filter(
6388
        $filename,
6389
        250,
6390
        '',
6391
        true,
6392
        true,
6393
        false,
6394
        false,
6395
        $treat_spaces_as_hyphens
6396
    );
6397
6398
    return $url;
6399
}
6400
6401
/**
6402
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6403
 *
6404
 * @author Ivan Tcholakov, 28-JUN-2006.
6405
 */
6406
function api_request_uri()
6407
{
6408
    if (!empty($_SERVER['REQUEST_URI'])) {
6409
        return $_SERVER['REQUEST_URI'];
6410
    }
6411
    $uri = $_SERVER['SCRIPT_NAME'];
6412
    if (!empty($_SERVER['QUERY_STRING'])) {
6413
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6414
    }
6415
    $_SERVER['REQUEST_URI'] = $uri;
6416
6417
    return $uri;
6418
}
6419
6420
/** Gets the current access_url id of the Chamilo Platform
6421
 * @author Julio Montoya <[email protected]>
6422
 *
6423
 * @return int access_url_id of the current Chamilo Installation
6424
 */
6425
function api_get_current_access_url_id()
6426
{
6427
    $access_url_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6428
    $path = Database::escape_string(api_get_path(WEB_PATH));
6429
    $sql = "SELECT id FROM $access_url_table WHERE url = '".$path."'";
6430
    $result = Database::query($sql);
6431
    if (Database::num_rows($result) > 0) {
6432
        $access_url_id = Database::result($result, 0, 0);
6433
        if ($access_url_id === false) {
6434
            return -1;
6435
        }
6436
6437
        return $access_url_id;
6438
    }
6439
6440
    //if the url in WEB_PATH was not found, it can only mean that there is
6441
    // either a configuration problem or the first URL has not been defined yet
6442
    // (by default it is http://localhost/). Thus the more sensible thing we can
6443
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6444
    return 1;
6445
}
6446
6447
/**
6448
 * Gets the registered urls from a given user id.
6449
 *
6450
 * @author Julio Montoya <[email protected]>
6451
 *
6452
 * @return int user id
6453
 */
6454
function api_get_access_url_from_user($user_id)
6455
{
6456
    $user_id = (int) $user_id;
6457
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6458
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6459
    $sql = "SELECT access_url_id
6460
            FROM $table_url_rel_user url_rel_user
6461
            INNER JOIN $table_url u
6462
            ON (url_rel_user.access_url_id = u.id)
6463
            WHERE user_id = ".intval($user_id);
6464
    $result = Database::query($sql);
6465
    $list = [];
6466
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6467
        $list[] = $row['access_url_id'];
6468
    }
6469
6470
    return $list;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $list returns the type array which is incompatible with the documented return type integer.
Loading history...
6471
}
6472
6473
/**
6474
 * Gets the status of a user in a course.
6475
 *
6476
 * @param int $user_id
6477
 * @param int $courseId
6478
 *
6479
 * @return int user status
6480
 */
6481
function api_get_status_of_user_in_course($user_id, $courseId)
6482
{
6483
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6484
    if (!empty($user_id) && !empty($courseId)) {
6485
        $user_id = intval($user_id);
6486
        $courseId = intval($courseId);
6487
        $sql = 'SELECT status
6488
                FROM '.$tbl_rel_course_user.'
6489
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6490
        $result = Database::query($sql);
6491
        $row_status = Database::fetch_array($result, 'ASSOC');
6492
6493
        return $row_status['status'];
6494
    } else {
6495
        return 0;
6496
    }
6497
}
6498
6499
/**
6500
 * Checks whether the curent user is in a group or not.
6501
 *
6502
 * @param string        The group id - optional (takes it from session if not given)
6503
 * @param string        The course code - optional (no additional check by course if course code is not given)
6504
 *
6505
 * @return bool
6506
 *
6507
 * @author Ivan Tcholakov
6508
 */
6509
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6510
{
6511
    if (!empty($courseCodeParam)) {
6512
        $courseCode = api_get_course_id();
6513
        if (!empty($courseCode)) {
6514
            if ($courseCodeParam != $courseCode) {
6515
                return false;
6516
            }
6517
        } else {
6518
            return false;
6519
        }
6520
    }
6521
6522
    $groupId = api_get_group_id();
6523
6524
    if (isset($groupId) && $groupId != '') {
6525
        if (!empty($groupIdParam)) {
6526
            return $groupIdParam == $groupId;
6527
        } else {
6528
            return true;
6529
        }
6530
    }
6531
6532
    return false;
6533
}
6534
6535
/**
6536
 * Checks whether a secret key is valid.
6537
 *
6538
 * @param string $original_key_secret - secret key from (webservice) client
6539
 * @param string $security_key        - security key from Chamilo
6540
 *
6541
 * @return bool - true if secret key is valid, false otherwise
6542
 */
6543
function api_is_valid_secret_key($original_key_secret, $security_key)
6544
{
6545
    return $original_key_secret == sha1($security_key);
6546
}
6547
6548
/**
6549
 * Checks whether a user is into course.
6550
 *
6551
 * @param int $course_id - the course id
6552
 * @param int $user_id   - the user id
6553
 *
6554
 * @return bool
6555
 */
6556
function api_is_user_of_course($course_id, $user_id)
6557
{
6558
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6559
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6560
            WHERE
6561
                c_id ="'.intval($course_id).'" AND
6562
                user_id = "'.intval($user_id).'" AND
6563
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6564
    $result = Database::query($sql);
6565
6566
    return Database::num_rows($result) == 1;
6567
}
6568
6569
/**
6570
 * Checks whether the server's operating system is Windows (TM).
6571
 *
6572
 * @return bool - true if the operating system is Windows, false otherwise
6573
 */
6574
function api_is_windows_os()
6575
{
6576
    if (function_exists('php_uname')) {
6577
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6578
        // We expect that this function will always work for Chamilo 1.8.x.
6579
        $os = php_uname();
6580
    }
6581
    // The following methods are not needed, but let them stay, just in case.
6582
    elseif (isset($_ENV['OS'])) {
6583
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6584
        $os = $_ENV['OS'];
6585
    } elseif (defined('PHP_OS')) {
6586
        // PHP_OS means on which OS PHP was compiled, this is why
6587
        // using PHP_OS is the last choice for detection.
6588
        $os = PHP_OS;
6589
    } else {
6590
        return false;
6591
    }
6592
6593
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6594
}
6595
6596
/**
6597
 * This function informs whether the sent request is XMLHttpRequest.
6598
 */
6599
function api_is_xml_http_request()
6600
{
6601
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6602
}
6603
6604
/**
6605
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6606
 *
6607
 * @see http://php.net/manual/en/function.getimagesize.php
6608
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6609
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6610
 *
6611
 * @return int
6612
 */
6613
function api_getimagesize($path)
6614
{
6615
    $image = new Image($path);
6616
6617
    return $image->get_image_size();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $image->get_image_size() returns the type array<string,integer>|array which is incompatible with the documented return type integer.
Loading history...
6618
}
6619
6620
/**
6621
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6622
 *
6623
 * @author Ivan Tcholakov, MAY-2009.
6624
 *
6625
 * @param int $image         System path or URL of the image
6626
 * @param int $target_width  Targeted width
6627
 * @param int $target_height Targeted height
6628
 *
6629
 * @return array Calculated new width and height
6630
 */
6631
function api_resize_image($image, $target_width, $target_height)
6632
{
6633
    $image_properties = api_getimagesize($image);
6634
6635
    return api_calculate_image_size(
6636
        $image_properties['width'],
6637
        $image_properties['height'],
6638
        $target_width,
6639
        $target_height
6640
    );
6641
}
6642
6643
/**
6644
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6645
 *
6646
 * @author Ivan Tcholakov, MAY-2009.
6647
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6648
 *
6649
 * @param int $image_width   Initial width
6650
 * @param int $image_height  Initial height
6651
 * @param int $target_width  Targeted width
6652
 * @param int $target_height Targeted height
6653
 *
6654
 * @return array Calculated new width and height
6655
 */
6656
function api_calculate_image_size(
6657
    $image_width,
6658
    $image_height,
6659
    $target_width,
6660
    $target_height
6661
) {
6662
    // Only maths is here.
6663
    $result = ['width' => $image_width, 'height' => $image_height];
6664
    if ($image_width <= 0 || $image_height <= 0) {
6665
        return $result;
6666
    }
6667
    $resize_factor_width = $target_width / $image_width;
6668
    $resize_factor_height = $target_height / $image_height;
6669
    $delta_width = $target_width - $image_width * $resize_factor_height;
6670
    $delta_height = $target_height - $image_height * $resize_factor_width;
6671
    if ($delta_width > $delta_height) {
6672
        $result['width'] = ceil($image_width * $resize_factor_height);
6673
        $result['height'] = ceil($image_height * $resize_factor_height);
6674
    } elseif ($delta_width < $delta_height) {
6675
        $result['width'] = ceil($image_width * $resize_factor_width);
6676
        $result['height'] = ceil($image_height * $resize_factor_width);
6677
    } else {
6678
        $result['width'] = ceil($target_width);
6679
        $result['height'] = ceil($target_height);
6680
    }
6681
6682
    return $result;
6683
}
6684
6685
/**
6686
 * Returns a list of Chamilo's tools or
6687
 * checks whether a given identificator is a valid Chamilo's tool.
6688
 *
6689
 * @author Isaac flores paz
6690
 *
6691
 * @param string The tool name to filter
6692
 *
6693
 * @return mixed Filtered string or array
6694
 */
6695
function api_get_tools_lists($my_tool = null)
6696
{
6697
    $tools_list = [
6698
        TOOL_DOCUMENT,
6699
        TOOL_THUMBNAIL,
6700
        TOOL_HOTPOTATOES,
6701
        TOOL_CALENDAR_EVENT,
6702
        TOOL_LINK,
6703
        TOOL_COURSE_DESCRIPTION,
6704
        TOOL_SEARCH,
6705
        TOOL_LEARNPATH,
6706
        TOOL_ANNOUNCEMENT,
6707
        TOOL_FORUM,
6708
        TOOL_THREAD,
6709
        TOOL_POST,
6710
        TOOL_DROPBOX,
6711
        TOOL_QUIZ,
6712
        TOOL_USER,
6713
        TOOL_GROUP,
6714
        TOOL_BLOGS,
6715
        TOOL_CHAT,
6716
        TOOL_STUDENTPUBLICATION,
6717
        TOOL_TRACKING,
6718
        TOOL_HOMEPAGE_LINK,
6719
        TOOL_COURSE_SETTING,
6720
        TOOL_BACKUP,
6721
        TOOL_COPY_COURSE_CONTENT,
6722
        TOOL_RECYCLE_COURSE,
6723
        TOOL_COURSE_HOMEPAGE,
6724
        TOOL_COURSE_RIGHTS_OVERVIEW,
6725
        TOOL_UPLOAD,
6726
        TOOL_COURSE_MAINTENANCE,
6727
        TOOL_SURVEY,
6728
        TOOL_WIKI,
6729
        TOOL_GLOSSARY,
6730
        TOOL_GRADEBOOK,
6731
        TOOL_NOTEBOOK,
6732
        TOOL_ATTENDANCE,
6733
        TOOL_COURSE_PROGRESS,
6734
    ];
6735
    if (empty($my_tool)) {
6736
        return $tools_list;
6737
    }
6738
6739
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6740
}
6741
6742
/**
6743
 * Checks whether we already approved the last version term and condition.
6744
 *
6745
 * @param int user id
6746
 *
6747
 * @return bool true if we pass false otherwise
6748
 */
6749
function api_check_term_condition($userId)
6750
{
6751
    if (api_get_setting('allow_terms_conditions') === 'true') {
6752
        // Check if exists terms and conditions
6753
        if (LegalManager::count() == 0) {
6754
            return true;
6755
        }
6756
6757
        $extraFieldValue = new ExtraFieldValue('user');
6758
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6759
            $userId,
6760
            'legal_accept'
6761
        );
6762
6763
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6764
            $result = $data['value'];
6765
            $user_conditions = explode(':', $result);
6766
            $version = $user_conditions[0];
6767
            $langId = $user_conditions[1];
6768
            $realVersion = LegalManager::get_last_version($langId);
6769
6770
            return $version >= $realVersion;
6771
        }
6772
6773
        return false;
6774
    }
6775
6776
    return false;
6777
}
6778
6779
/**
6780
 * Gets all information of a tool into course.
6781
 *
6782
 * @param int The tool id
6783
 *
6784
 * @return array
6785
 */
6786
function api_get_tool_information_by_name($name)
6787
{
6788
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6789
    $course_id = api_get_course_int_id();
6790
    $sql = "SELECT * FROM $t_tool
6791
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
6792
    $rs = Database::query($sql);
6793
6794
    return Database::fetch_array($rs, 'ASSOC');
6795
}
6796
6797
/**
6798
 * Function used to protect a "global" admin script.
6799
 * The function blocks access when the user has no global platform admin rights.
6800
 * Global admins are the admins that are registered in the main.admin table
6801
 * AND the users who have access to the "principal" portal.
6802
 * That means that there is a record in the main.access_url_rel_user table
6803
 * with his user id and the access_url_id=1.
6804
 *
6805
 * @author Julio Montoya
6806
 *
6807
 * @param int $user_id
6808
 *
6809
 * @return bool
6810
 */
6811
function api_is_global_platform_admin($user_id = null)
6812
{
6813
    $user_id = (int) $user_id;
6814
    if (empty($user_id)) {
6815
        $user_id = api_get_user_id();
6816
    }
6817
    if (api_is_platform_admin_by_id($user_id)) {
6818
        $urlList = api_get_access_url_from_user($user_id);
6819
        // The admin is registered in the first "main" site with access_url_id = 1
6820
        if (in_array(1, $urlList)) {
6821
            return true;
6822
        } else {
6823
            return false;
6824
        }
6825
    }
6826
6827
    return false;
6828
}
6829
6830
/**
6831
 * @param int  $admin_id_to_check
6832
 * @param int  $my_user_id
6833
 * @param bool $allow_session_admin
6834
 *
6835
 * @return bool
6836
 */
6837
function api_global_admin_can_edit_admin(
6838
    $admin_id_to_check,
6839
    $my_user_id = null,
6840
    $allow_session_admin = false
6841
) {
6842
    if (empty($my_user_id)) {
6843
        $my_user_id = api_get_user_id();
6844
    }
6845
6846
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6847
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6848
6849
    if ($iam_a_global_admin) {
6850
        // Global admin can edit everything
6851
        return true;
6852
    } else {
6853
        // If i'm a simple admin
6854
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6855
6856
        if ($allow_session_admin) {
6857
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
6858
        }
6859
6860
        if ($is_platform_admin) {
6861
            if ($user_is_global_admin) {
6862
                return false;
6863
            } else {
6864
                return true;
6865
            }
6866
        } else {
6867
            return false;
6868
        }
6869
    }
6870
}
6871
6872
/**
6873
 * @param int  $admin_id_to_check
6874
 * @param int  $my_user_id
6875
 * @param bool $allow_session_admin
6876
 *
6877
 * @return bool|null
6878
 */
6879
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6880
{
6881
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6882
        return true;
6883
    } else {
6884
        api_not_allowed();
6885
    }
6886
}
6887
6888
/**
6889
 * Function used to protect a global admin script.
6890
 * The function blocks access when the user has no global platform admin rights.
6891
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6892
 *
6893
 * @author Julio Montoya
6894
 */
6895
function api_protect_global_admin_script()
6896
{
6897
    if (!api_is_global_platform_admin()) {
6898
        api_not_allowed();
6899
6900
        return false;
6901
    }
6902
6903
    return true;
6904
}
6905
6906
/**
6907
 * Get active template.
6908
 *
6909
 * @param string    theme type (optional: default)
6910
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
6911
 *
6912
 * @return string actived template path
6913
 */
6914
function api_get_template($path_type = 'rel')
6915
{
6916
    $path_types = ['rel', 'abs'];
6917
    $template_path = '';
6918
    if (in_array($path_type, $path_types)) {
6919
        if ($path_type == 'rel') {
6920
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
6921
        } else {
6922
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
6923
        }
6924
    }
6925
    $actived_theme = 'default';
6926
    if (api_get_setting('active_template')) {
6927
        $actived_theme = api_get_setting('active_template');
6928
    }
6929
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
6930
6931
    return $actived_theme_path;
6932
}
6933
6934
/**
6935
 * Check browser support for specific file types or features
6936
 * This function checks if the user's browser supports a file format or given
6937
 * feature, or returns the current browser and major version when
6938
 * $format=check_browser. Only a limited number of formats and features are
6939
 * checked by this method. Make sure you check its definition first.
6940
 *
6941
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6942
 *
6943
 * @return bool or return text array if $format=check_browser
6944
 *
6945
 * @author Juan Carlos Raña Trabado
6946
 */
6947
function api_browser_support($format = '')
6948
{
6949
    $browser = new Browser();
6950
    $current_browser = $browser->getBrowser();
6951
    $a_versiontemp = explode('.', $browser->getVersion());
6952
    $current_majorver = $a_versiontemp[0];
6953
6954
    static $result;
6955
6956
    if (isset($result[$format])) {
6957
        return $result[$format];
6958
    }
6959
6960
    // Native svg support
6961
    if ($format == 'svg') {
6962
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6963
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
6964
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
6965
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
6966
            ($current_browser == 'Opera' && $current_majorver >= 9)
6967
        ) {
6968
            $result[$format] = true;
6969
6970
            return true;
6971
        } else {
6972
            $result[$format] = false;
6973
6974
            return false;
6975
        }
6976
    } elseif ($format == 'pdf') {
6977
        // native pdf support
6978
        if ($current_browser == 'Chrome' && $current_majorver >= 6) {
6979
            $result[$format] = true;
6980
6981
            return true;
6982
        } else {
6983
            $result[$format] = false;
6984
6985
            return false;
6986
        }
6987
    } elseif ($format == 'tif' || $format == 'tiff') {
6988
        //native tif support
6989
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6990
            $result[$format] = true;
6991
6992
            return true;
6993
        } else {
6994
            $result[$format] = false;
6995
6996
            return false;
6997
        }
6998
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
6999
        //native ogg, ogv,oga support
7000
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
7001
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
7002
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
7003
            $result[$format] = true;
7004
7005
            return true;
7006
        } else {
7007
            $result[$format] = false;
7008
7009
            return false;
7010
        }
7011
    } elseif ($format == 'mpg' || $format == 'mpeg') {
7012
        //native mpg support
7013
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
7014
            $result[$format] = true;
7015
7016
            return true;
7017
        } else {
7018
            $result[$format] = false;
7019
7020
            return false;
7021
        }
7022
    } elseif ($format == 'mp4') {
7023
        //native mp4 support (TODO: Android, iPhone)
7024
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
7025
            $result[$format] = true;
7026
7027
            return true;
7028
        } else {
7029
            $result[$format] = false;
7030
7031
            return false;
7032
        }
7033
    } elseif ($format == 'mov') {
7034
        //native mov support( TODO:check iPhone)
7035
        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...
7036
            $result[$format] = true;
7037
7038
            return true;
7039
        } else {
7040
            $result[$format] = false;
7041
7042
            return false;
7043
        }
7044
    } elseif ($format == 'avi') {
7045
        //native avi support
7046
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7047
            $result[$format] = true;
7048
7049
            return true;
7050
        } else {
7051
            $result[$format] = false;
7052
7053
            return false;
7054
        }
7055
    } elseif ($format == 'wmv') {
7056
        //native wmv support
7057
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7058
            $result[$format] = true;
7059
7060
            return true;
7061
        } else {
7062
            $result[$format] = false;
7063
7064
            return false;
7065
        }
7066
    } elseif ($format == 'webm') {
7067
        //native webm support (TODO:check IE9, Chrome9, Android)
7068
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7069
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7070
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7071
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
7072
            $current_browser == 'Android'
7073
        ) {
7074
            $result[$format] = true;
7075
7076
            return true;
7077
        } else {
7078
            $result[$format] = false;
7079
7080
            return false;
7081
        }
7082
    } elseif ($format == 'wav') {
7083
        //native wav support (only some codecs !)
7084
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7085
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
7086
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7087
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7088
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
7089
            $current_browser == 'Android' ||
7090
            $current_browser == 'iPhone'
7091
        ) {
7092
            $result[$format] = true;
7093
7094
            return true;
7095
        } else {
7096
            $result[$format] = false;
7097
7098
            return false;
7099
        }
7100
    } elseif ($format == 'mid' || $format == 'kar') {
7101
        //native midi support (TODO:check Android)
7102
        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...
7103
            $result[$format] = true;
7104
7105
            return true;
7106
        } else {
7107
            $result[$format] = false;
7108
7109
            return false;
7110
        }
7111
    } elseif ($format == 'wma') {
7112
        //native wma support
7113
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7114
            $result[$format] = true;
7115
7116
            return true;
7117
        } else {
7118
            $result[$format] = false;
7119
7120
            return false;
7121
        }
7122
    } elseif ($format == 'au') {
7123
        //native au support
7124
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7125
            $result[$format] = true;
7126
7127
            return true;
7128
        } else {
7129
            $result[$format] = false;
7130
7131
            return false;
7132
        }
7133
    } elseif ($format == 'mp3') {
7134
        //native mp3 support (TODO:check Android, iPhone)
7135
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
7136
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
7137
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7138
            $current_browser == 'Android' ||
7139
            $current_browser == 'iPhone' ||
7140
            $current_browser == 'Firefox'
7141
        ) {
7142
            $result[$format] = true;
7143
7144
            return true;
7145
        } else {
7146
            $result[$format] = false;
7147
7148
            return false;
7149
        }
7150
    } elseif ($format == 'autocapitalize') {
7151
        // Help avoiding showing the autocapitalize option if the browser doesn't
7152
        // support it: this attribute is against the HTML5 standard
7153
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
7154
            return true;
7155
        } else {
7156
            return false;
7157
        }
7158
    } elseif ($format == "check_browser") {
7159
        $array_check_browser = [$current_browser, $current_majorver];
7160
7161
        return $array_check_browser;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $array_check_browser returns the type array<integer,mixed|string> which is incompatible with the documented return type boolean.
Loading history...
7162
    } else {
7163
        $result[$format] = false;
7164
7165
        return false;
7166
    }
7167
}
7168
7169
/**
7170
 * This function checks if exist path and file browscap.ini
7171
 * In order for this to work, your browscap configuration setting in php.ini
7172
 * must point to the correct location of the browscap.ini file on your system
7173
 * http://php.net/manual/en/function.get-browser.php.
7174
 *
7175
 * @return bool
7176
 *
7177
 * @author Juan Carlos Raña Trabado
7178
 */
7179
function api_check_browscap()
7180
{
7181
    $setting = ini_get('browscap');
7182
    if ($setting) {
7183
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7184
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7185
            return true;
7186
        }
7187
    }
7188
7189
    return false;
7190
}
7191
7192
/**
7193
 * Returns the <script> HTML tag.
7194
 */
7195
function api_get_js($file)
7196
{
7197
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7198
}
7199
7200
/**
7201
 * Returns the <script> HTML tag.
7202
 *
7203
 * @return string
7204
 */
7205
function api_get_asset($file)
7206
{
7207
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'"></script>'."\n";
7208
}
7209
7210
/**
7211
 * Returns the <script> HTML tag.
7212
 *
7213
 * @param string $file
7214
 * @param string $media
7215
 *
7216
 * @return string
7217
 */
7218
function api_get_css_asset($file, $media = 'screen')
7219
{
7220
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7221
}
7222
7223
/**
7224
 * Returns the <link> HTML tag.
7225
 *
7226
 * @param string $file
7227
 * @param string $media
7228
 */
7229
function api_get_css($file, $media = 'screen')
7230
{
7231
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7232
}
7233
7234
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
7235
{
7236
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
7237
    if ($returnOnlyPath) {
7238
        return $url;
7239
    }
7240
7241
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
7242
}
7243
7244
/**
7245
 * Returns the js header to include the jquery library.
7246
 */
7247
function api_get_jquery_js()
7248
{
7249
    return api_get_asset('jquery/dist/jquery.min.js');
7250
}
7251
7252
/**
7253
 * Returns the jquery path.
7254
 *
7255
 * @return string
7256
 */
7257
function api_get_jquery_web_path()
7258
{
7259
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
7260
}
7261
7262
/**
7263
 * @return string
7264
 */
7265
function api_get_jquery_ui_js_web_path()
7266
{
7267
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7268
}
7269
7270
/**
7271
 * @return string
7272
 */
7273
function api_get_jquery_ui_css_web_path()
7274
{
7275
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7276
}
7277
7278
/**
7279
 * Returns the jquery-ui library js headers.
7280
 *
7281
 * @param   bool    add the jqgrid library
7282
 *
7283
 * @return string html tags
7284
 */
7285
function api_get_jquery_ui_js($include_jqgrid = false)
7286
{
7287
    $libraries = [];
7288
    if ($include_jqgrid) {
7289
        $libraries[] = 'jqgrid';
7290
    }
7291
7292
    return api_get_jquery_libraries_js($libraries);
7293
}
7294
7295
function api_get_jqgrid_js()
7296
{
7297
    return api_get_jquery_libraries_js(['jqgrid']);
7298
}
7299
7300
/**
7301
 * Returns the jquery library js and css headers.
7302
 *
7303
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
7304
 * @param   bool    add the jquery library
7305
 *
7306
 * @return string html tags
7307
 */
7308
function api_get_jquery_libraries_js($libraries)
7309
{
7310
    $js = '';
7311
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
7312
7313
    //jqgrid js and css
7314
    if (in_array('jqgrid', $libraries)) {
7315
        $languaje = 'en';
7316
        $platform_isocode = strtolower(api_get_language_isocode());
7317
7318
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7319
        $jqgrid_langs = [
7320
            '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',
7321
        ];
7322
7323
        if (in_array($platform_isocode, $jqgrid_langs)) {
7324
            $languaje = $platform_isocode;
7325
        }
7326
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
7327
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
7328
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
7329
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
7330
    }
7331
7332
    //Document multiple upload funcionality
7333
    if (in_array('jquery-uploadzs', $libraries)) {
7334
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7335
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7336
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7337
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7338
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7339
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7340
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7341
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7342
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7343
7344
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7345
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7346
    }
7347
7348
    // jquery datepicker
7349
    if (in_array('datepicker', $libraries)) {
7350
        $languaje = 'en-GB';
7351
        $platform_isocode = strtolower(api_get_language_isocode());
7352
7353
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7354
        $datapicker_langs = [
7355
            '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',
7356
        ];
7357
        if (in_array($platform_isocode, $datapicker_langs)) {
7358
            $languaje = $platform_isocode;
7359
        }
7360
7361
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7362
        $script = '<script>
7363
        $(function(){
7364
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7365
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7366
        });
7367
        </script>
7368
        ';
7369
        $js .= $script;
7370
    }
7371
7372
    return $js;
7373
}
7374
7375
/**
7376
 * Returns the URL to the course or session, removing the complexity of the URL
7377
 * building piece by piece.
7378
 *
7379
 * This function relies on api_get_course_info()
7380
 *
7381
 * @param string $courseCode The course code - optional (takes it from context if not given)
7382
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7383
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7384
 *
7385
 * @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
7386
 *
7387
 * @author  Julio Montoya <[email protected]>
7388
 */
7389
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7390
{
7391
    $courseDirectory = '';
7392
    $url = '';
7393
    // If courseCode not set, get context or []
7394
    if (empty($courseCode)) {
7395
        $courseInfo = api_get_course_info();
7396
    } else {
7397
        $courseInfo = api_get_course_info($courseCode);
7398
    }
7399
7400
    // If course defined, get directory, otherwise keep empty string
7401
    if (!empty($courseInfo['directory'])) {
7402
        $courseDirectory = $courseInfo['directory'];
7403
    }
7404
7405
    // If sessionId not set, get context or 0
7406
    if (empty($sessionId)) {
7407
        $sessionId = api_get_session_id();
7408
    }
7409
7410
    // If groupId not set, get context or 0
7411
    if (empty($groupId)) {
7412
        $groupId = api_get_group_id();
7413
    }
7414
7415
    // Build the URL
7416
    if (!empty($courseDirectory)) {
7417
        // directory not empty, so we do have a course
7418
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7419
    } elseif (!empty($sessionId) &&
7420
        api_get_setting('session.remove_session_url') !== 'true'
7421
    ) {
7422
        // if the course was unset and the session was set, send directly to the session
7423
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7424
    }
7425
7426
    // if not valid combination was found, return an empty string
7427
    return $url;
7428
}
7429
7430
/**
7431
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7432
 *
7433
 * @return bool true if multi site is enabled
7434
 */
7435
function api_get_multiple_access_url()
7436
{
7437
    global $_configuration;
7438
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7439
        return true;
7440
    }
7441
7442
    return false;
7443
}
7444
7445
/**
7446
 * @return bool
7447
 */
7448
function api_is_multiple_url_enabled()
7449
{
7450
    return api_get_multiple_access_url();
7451
}
7452
7453
/**
7454
 * Returns a md5 unique id.
7455
 *
7456
 * @todo add more parameters
7457
 */
7458
function api_get_unique_id()
7459
{
7460
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7461
7462
    return $id;
7463
}
7464
7465
/**
7466
 * Get home path.
7467
 *
7468
 * @return string
7469
 */
7470
function api_get_home_path()
7471
{
7472
    // FIX : Start the routing determination from central path definition
7473
    $home = api_get_path(SYS_HOME_PATH);
7474
    if (api_get_multiple_access_url()) {
7475
        $access_url_id = api_get_current_access_url_id();
7476
        $url_info = api_get_access_url($access_url_id);
7477
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
7478
        $clean_url = api_replace_dangerous_char($url);
7479
        $clean_url = str_replace('/', '-', $clean_url);
7480
        $clean_url .= '/';
7481
        if ($clean_url != 'localhost/') {
7482
            // means that the multiple URL was not well configured we don't rename the $home variable
7483
            return "{$home}{$clean_url}";
7484
        }
7485
    }
7486
7487
    return $home;
7488
}
7489
7490
/**
7491
 * @param int Course id
7492
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7493
 * @param int the item id (tool id, exercise id, lp id)
7494
 *
7495
 * @return bool
7496
 */
7497
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7498
{
7499
    if (api_is_platform_admin()) {
7500
        return false;
7501
    }
7502
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
7503
        if (empty($course_code)) {
7504
            $course_code = api_get_course_id();
7505
        }
7506
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7507
        $item_id = intval($item_id);
7508
        $link_type = intval($link_type);
7509
        $course_code = Database::escape_string($course_code);
7510
        $sql = "SELECT locked FROM $table
7511
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7512
        $result = Database::query($sql);
7513
        if (Database::num_rows($result)) {
7514
            return true;
7515
        }
7516
    }
7517
7518
    return false;
7519
}
7520
7521
/**
7522
 * Blocks a page if the item was added in a gradebook.
7523
 *
7524
 * @param int       exercise id, work id, thread id,
7525
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7526
 * see gradebook/lib/be/linkfactory
7527
 * @param string    course code
7528
 *
7529
 * @return false|null
7530
 */
7531
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7532
{
7533
    if (api_is_platform_admin()) {
7534
        return false;
7535
    }
7536
7537
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7538
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
7539
        api_not_allowed(true, $message);
7540
    }
7541
}
7542
7543
/**
7544
 * Checks the PHP version installed is enough to run Chamilo.
7545
 *
7546
 * @param string Include path (used to load the error page)
7547
 */
7548
function api_check_php_version($my_inc_path = null)
7549
{
7550
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
7551
        $global_error_code = 1;
7552
        // Incorrect PHP version
7553
        $global_page = $my_inc_path.'global_error_message.inc.php';
7554
        if (file_exists($global_page)) {
7555
            require $global_page;
7556
        }
7557
        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...
7558
    }
7559
}
7560
7561
/**
7562
 * Checks whether the Archive directory is present and writeable. If not,
7563
 * prints a warning message.
7564
 */
7565
function api_check_archive_dir()
7566
{
7567
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7568
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
7569
        api_not_allowed(true, $message);
7570
    }
7571
}
7572
7573
/**
7574
 * Returns an array of global configuration settings which should be ignored
7575
 * when printing the configuration settings screens.
7576
 *
7577
 * @return array Array of strings, each identifying one of the excluded settings
7578
 */
7579
function api_get_locked_settings()
7580
{
7581
    return [
7582
        'permanently_remove_deleted_files',
7583
        'account_valid_duration',
7584
        'service_ppt2lp',
7585
        'wcag_anysurfer_public_pages',
7586
        'upload_extensions_list_type',
7587
        'upload_extensions_blacklist',
7588
        'upload_extensions_whitelist',
7589
        'upload_extensions_skip',
7590
        'upload_extensions_replace_by',
7591
        'hide_dltt_markup',
7592
        'split_users_upload_directory',
7593
        'permissions_for_new_directories',
7594
        'permissions_for_new_files',
7595
        'platform_charset',
7596
        'ldap_description',
7597
        'cas_activate',
7598
        'cas_server',
7599
        'cas_server_uri',
7600
        'cas_port',
7601
        'cas_protocol',
7602
        'cas_add_user_activate',
7603
        'update_user_info_cas_with_ldap',
7604
        'languagePriority1',
7605
        'languagePriority2',
7606
        'languagePriority3',
7607
        'languagePriority4',
7608
        'login_is_email',
7609
        'chamilo_database_version',
7610
    ];
7611
}
7612
7613
/**
7614
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7615
 * false if he isn't. If the user ID is given and is an integer, then the same
7616
 * ID is simply returned.
7617
 *
7618
 * @param  int User ID
7619
 *
7620
 * @return bool Integer User ID is logged in, or false otherwise
7621
 */
7622
function api_user_is_login($user_id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $user_id is not used and could be removed. ( Ignorable by Annotation )

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

7622
function api_user_is_login(/** @scrutinizer ignore-unused */ $user_id = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
7623
{
7624
    return Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
7625
}
7626
7627
/**
7628
 * Guess the real ip for register in the database, even in reverse proxy cases.
7629
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7630
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7631
 * Note: the result of this function is not SQL-safe. Please escape it before
7632
 * inserting in a database.
7633
 *
7634
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7635
 *
7636
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7637
 *
7638
 * @version CEV CHANGE 24APR2012
7639
 */
7640
function api_get_real_ip()
7641
{
7642
    // Guess the IP if behind a reverse proxy
7643
    global $debug;
7644
    $ip = trim($_SERVER['REMOTE_ADDR']);
7645
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7646
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7647
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7648
        } else {
7649
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7650
        }
7651
        $ip = trim($ip1);
7652
    }
7653
    if (!empty($debug)) {
7654
        error_log('Real IP: '.$ip);
7655
    }
7656
7657
    return $ip;
7658
}
7659
7660
/**
7661
 * Checks whether an IP is included inside an IP range.
7662
 *
7663
 * @param string IP address
7664
 * @param string IP range
7665
 * @param string $ip
7666
 *
7667
 * @return bool True if IP is in the range, false otherwise
7668
 *
7669
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7670
 * @author Yannick Warnier for improvements and managment of multiple ranges
7671
 *
7672
 * @todo check for IPv6 support
7673
 */
7674
function api_check_ip_in_range($ip, $range)
7675
{
7676
    if (empty($ip) or empty($range)) {
7677
        return false;
7678
    }
7679
    $ip_ip = ip2long($ip);
7680
    // divide range param into array of elements
7681
    if (strpos($range, ',') !== false) {
7682
        $ranges = explode(',', $range);
7683
    } else {
7684
        $ranges = [$range];
7685
    }
7686
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7687
        $range = trim($range);
7688
        if (empty($range)) {
7689
            continue;
7690
        }
7691
        if (strpos($range, '/') === false) {
7692
            if (strcmp($ip, $range) === 0) {
7693
                return true; // there is a direct IP match, return OK
7694
            }
7695
            continue; //otherwise, get to the next range
7696
        }
7697
        // the range contains a "/", so analyse completely
7698
        list($net, $mask) = explode("/", $range);
7699
7700
        $ip_net = ip2long($net);
7701
        // mask binary magic
7702
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7703
7704
        $ip_ip_net = $ip_ip & $ip_mask;
7705
        if ($ip_ip_net == $ip_net) {
7706
            return true;
7707
        }
7708
    }
7709
7710
    return false;
7711
}
7712
7713
function api_check_user_access_to_legal($course_visibility)
7714
{
7715
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7716
7717
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7718
}
7719
7720
/**
7721
 * Checks if the global chat is enabled or not.
7722
 *
7723
 * @return bool
7724
 */
7725
function api_is_global_chat_enabled()
7726
{
7727
    return
7728
        !api_is_anonymous() &&
7729
        api_get_setting('allow_global_chat') === 'true' &&
7730
        api_get_setting('allow_social_tool') === 'true';
7731
}
7732
7733
/**
7734
 * @todo Fix tool_visible_by_default_at_creation labels
7735
 * @todo Add sessionId parameter to avoid using context
7736
 *
7737
 * @param int   $item_id
7738
 * @param int   $tool_id
7739
 * @param int   $group_id   id
7740
 * @param array $courseInfo
7741
 * @param int   $sessionId
7742
 * @param int   $userId
7743
 */
7744
function api_set_default_visibility(
7745
    $item_id,
7746
    $tool_id,
7747
    $group_id = 0,
7748
    $courseInfo = [],
7749
    $sessionId = 0,
7750
    $userId = 0
7751
) {
7752
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7753
    $courseId = $courseInfo['real_id'];
7754
    $courseCode = $courseInfo['code'];
7755
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7756
    $userId = empty($userId) ? api_get_user_id() : $userId;
7757
7758
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7759
    if (is_null($group_id)) {
7760
        $group_id = 0;
7761
    } else {
7762
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7763
    }
7764
7765
    $groupInfo = [];
7766
    if (!empty($group_id)) {
7767
        $groupInfo = GroupManager::get_group_properties($group_id);
7768
    }
7769
    $original_tool_id = $tool_id;
7770
7771
    switch ($tool_id) {
7772
        case TOOL_LINK:
7773
        case TOOL_LINK_CATEGORY:
7774
            $tool_id = 'links';
7775
            break;
7776
        case TOOL_DOCUMENT:
7777
            $tool_id = 'documents';
7778
            break;
7779
        case TOOL_LEARNPATH:
7780
            $tool_id = 'learning';
7781
            break;
7782
        case TOOL_ANNOUNCEMENT:
7783
            $tool_id = 'announcements';
7784
            break;
7785
        case TOOL_FORUM:
7786
        case TOOL_FORUM_CATEGORY:
7787
        case TOOL_FORUM_THREAD:
7788
            $tool_id = 'forums';
7789
            break;
7790
        case TOOL_QUIZ:
7791
            $tool_id = 'quiz';
7792
            break;
7793
    }
7794
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7795
7796
    if (isset($setting[$tool_id])) {
7797
        $visibility = 'invisible';
7798
        if ($setting[$tool_id] == 'true') {
7799
            $visibility = 'visible';
7800
        }
7801
7802
        // Read the portal and course default visibility
7803
        if ($tool_id == 'documents') {
7804
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseCode);
7805
        }
7806
7807
        api_item_property_update(
7808
            $courseInfo,
7809
            $original_tool_id,
7810
            $item_id,
7811
            $visibility,
7812
            $userId,
7813
            $groupInfo,
7814
            null,
7815
            null,
7816
            null,
7817
            $sessionId
7818
        );
7819
7820
        // Fixes default visibility for tests
7821
        switch ($original_tool_id) {
7822
            case TOOL_QUIZ:
7823
                if (empty($sessionId)) {
7824
                    $objExerciseTmp = new Exercise($courseId);
7825
                    $objExerciseTmp->read($item_id);
7826
                    if ($visibility == 'visible') {
7827
                        $objExerciseTmp->enable();
7828
                        $objExerciseTmp->save();
7829
                    } else {
7830
                        $objExerciseTmp->disable();
7831
                        $objExerciseTmp->save();
7832
                    }
7833
                }
7834
                break;
7835
        }
7836
    }
7837
}
7838
7839
/**
7840
 * @return string
7841
 */
7842
function api_get_security_key()
7843
{
7844
    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...
7845
}
7846
7847
/**
7848
 * @param int $user_id
7849
 * @param int $courseId
7850
 * @param int $session_id
7851
 *
7852
 * @return array
7853
 */
7854
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7855
{
7856
    $user_roles = [];
7857
    $courseInfo = api_get_course_info_by_id($courseId);
7858
    $course_code = $courseInfo['code'];
7859
7860
    $url_id = api_get_current_access_url_id();
7861
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7862
        $user_roles[] = PLATFORM_ADMIN;
7863
    }
7864
7865
    /*if (api_is_drh()) {
7866
        $user_roles[] = DRH;
7867
    }*/
7868
7869
    if (!empty($session_id)) {
7870
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7871
            $user_roles[] = SESSION_GENERAL_COACH;
7872
        }
7873
    }
7874
7875
    if (!empty($course_code)) {
7876
        if (empty($session_id)) {
7877
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7878
                $user_roles[] = COURSEMANAGER;
7879
            }
7880
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7881
                $user_roles[] = COURSE_TUTOR;
7882
            }
7883
7884
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7885
                $user_roles[] = COURSE_STUDENT;
7886
            }
7887
        } else {
7888
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7889
                $user_id,
7890
                $courseId,
7891
                $session_id
7892
            );
7893
7894
            if (!empty($user_status_in_session)) {
7895
                if ($user_status_in_session == 0) {
7896
                    $user_roles[] = SESSION_STUDENT;
7897
                }
7898
                if ($user_status_in_session == 2) {
7899
                    $user_roles[] = SESSION_COURSE_COACH;
7900
                }
7901
            }
7902
7903
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7904
               $user_roles[] = SESSION_COURSE_COACH;
7905
            }*/
7906
        }
7907
    }
7908
7909
    return $user_roles;
7910
}
7911
7912
/**
7913
 * @param int $courseId
7914
 * @param int $session_id
7915
 *
7916
 * @return bool
7917
 */
7918
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7919
{
7920
    if (api_is_platform_admin()) {
7921
        return true;
7922
    }
7923
7924
    $user_id = api_get_user_id();
7925
7926
    if (empty($courseId)) {
7927
        $courseId = api_get_course_int_id();
7928
    }
7929
7930
    if (empty($session_id)) {
7931
        $session_id = api_get_session_id();
7932
    }
7933
7934
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7935
7936
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7937
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7938
        return true;
7939
    } else {
7940
        if (in_array(COURSEMANAGER, $roles)) {
7941
            return true;
7942
        }
7943
7944
        return false;
7945
    }
7946
}
7947
7948
/**
7949
 * @param string $file
7950
 *
7951
 * @return string
7952
 */
7953
function api_get_js_simple($file)
7954
{
7955
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7956
}
7957
7958
function api_set_settings_and_plugins()
7959
{
7960
    global $_configuration;
7961
    $_setting = [];
7962
    $_plugins = [];
7963
7964
    // access_url == 1 is the default chamilo location
7965
    $settings_by_access_list = [];
7966
    $access_url_id = api_get_current_access_url_id();
7967
    if ($access_url_id != 1) {
7968
        $url_info = api_get_access_url($_configuration['access_url']);
7969
        if ($url_info['active'] == 1) {
7970
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
7971
            foreach ($settings_by_access as &$row) {
7972
                if (empty($row['variable'])) {
7973
                    $row['variable'] = 0;
7974
                }
7975
                if (empty($row['subkey'])) {
7976
                    $row['subkey'] = 0;
7977
                }
7978
                if (empty($row['category'])) {
7979
                    $row['category'] = 0;
7980
                }
7981
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
7982
            }
7983
        }
7984
    }
7985
7986
    $result = api_get_settings(null, 'list', 1);
7987
7988
    foreach ($result as &$row) {
7989
        if ($access_url_id != 1) {
7990
            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...
7991
                $var = empty($row['variable']) ? 0 : $row['variable'];
7992
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
7993
                $category = empty($row['category']) ? 0 : $row['category'];
7994
            }
7995
7996
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
7997
                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...
7998
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $subkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
7999
                    if ($row['subkey'] == null) {
8000
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8001
                    } else {
8002
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8003
                    }
8004
                } else {
8005
                    if ($row['subkey'] == null) {
8006
                        $_setting[$row['variable']] = $row['selected_value'];
8007
                    } else {
8008
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8009
                    }
8010
                }
8011
            } else {
8012
                if ($row['subkey'] == null) {
8013
                    $_setting[$row['variable']] = $row['selected_value'];
8014
                } else {
8015
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8016
                }
8017
            }
8018
        } else {
8019
            if ($row['subkey'] == null) {
8020
                $_setting[$row['variable']] = $row['selected_value'];
8021
            } else {
8022
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8023
            }
8024
        }
8025
    }
8026
8027
    $result = api_get_settings('Plugins', 'list', $access_url_id);
8028
    $_plugins = [];
8029
    foreach ($result as &$row) {
8030
        $key = &$row['variable'];
8031
        if (is_string($_setting[$key])) {
8032
            $_setting[$key] = [];
8033
        }
8034
        $_setting[$key][] = $row['selected_value'];
8035
        $_plugins[$key][] = $row['selected_value'];
8036
    }
8037
8038
    $_SESSION['_setting'] = $_setting;
8039
    $_SESSION['_plugins'] = $_plugins;
8040
}
8041
8042
/**
8043
 * Modify default memory_limit and max_execution_time limits
8044
 * Needed when processing long tasks.
8045
 */
8046
function api_set_more_memory_and_time_limits()
8047
{
8048
    if (function_exists('ini_set')) {
8049
        api_set_memory_limit('256M');
8050
        ini_set('max_execution_time', 1800);
8051
    }
8052
}
8053
8054
/**
8055
 * Tries to set memory limit, if authorized and new limit is higher than current.
8056
 *
8057
 * @param string $mem New memory limit
8058
 *
8059
 * @return bool True on success, false on failure or current is higher than suggested
8060
 * @assert (null) === false
8061
 * @assert (-1) === false
8062
 * @assert (0) === true
8063
 * @assert ('1G') === true
8064
 */
8065
function api_set_memory_limit($mem)
8066
{
8067
    //if ini_set() not available, this function is useless
8068
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
8069
        return false;
8070
    }
8071
8072
    $memory_limit = ini_get('memory_limit');
8073
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8074
        ini_set('memory_limit', $mem);
8075
8076
        return true;
8077
    }
8078
8079
    return false;
8080
}
8081
8082
/**
8083
 * Gets memory limit in bytes.
8084
 *
8085
 * @param string The memory size (128M, 1G, 1000K, etc)
8086
 *
8087
 * @return int
8088
 * @assert (null) === false
8089
 * @assert ('1t')  === 1099511627776
8090
 * @assert ('1g')  === 1073741824
8091
 * @assert ('1m')  === 1048576
8092
 * @assert ('100k') === 102400
8093
 */
8094
function api_get_bytes_memory_limit($mem)
8095
{
8096
    $size = strtolower(substr($mem, -1));
8097
8098
    switch ($size) {
8099
        case 't':
8100
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8101
            break;
8102
        case 'g':
8103
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8104
            break;
8105
        case 'm':
8106
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8107
            break;
8108
        case 'k':
8109
            $mem = intval(substr($mem, 0, -1)) * 1024;
8110
            break;
8111
        default:
8112
            // we assume it's integer only
8113
            $mem = intval($mem);
8114
            break;
8115
    }
8116
8117
    return $mem;
8118
}
8119
8120
/**
8121
 * Finds all the information about a user from username instead of user id.
8122
 *
8123
 * @param string $officialCode
8124
 *
8125
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8126
 *
8127
 * @author Yannick Warnier <[email protected]>
8128
 */
8129
function api_get_user_info_from_official_code($officialCode)
8130
{
8131
    if (empty($officialCode)) {
8132
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
8133
    }
8134
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8135
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8136
    $result = Database::query($sql);
8137
    if (Database::num_rows($result) > 0) {
8138
        $result_array = Database::fetch_array($result);
8139
8140
        return _api_format_user($result_array);
8141
    }
8142
8143
    return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
8144
}
8145
8146
/**
8147
 * @param string $usernameInputId
8148
 * @param string $passwordInputId
8149
 *
8150
 * @return null|string
8151
 */
8152
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8153
{
8154
    $checkPass = api_get_setting('allow_strength_pass_checker');
8155
    $useStrengthPassChecker = $checkPass === 'true';
8156
8157
    if ($useStrengthPassChecker === false) {
8158
        return null;
8159
    }
8160
8161
    $translations = [
8162
        'wordLength' => get_lang('PasswordIsTooShort'),
8163
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
8164
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
8165
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
8166
        'wordRepetitions' => get_lang('TooManyRepetitions'),
8167
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
8168
        'errorList' => get_lang('ErrorsFound'),
8169
        'veryWeak' => get_lang('PasswordVeryWeak'),
8170
        'weak' => get_lang('PasswordWeak'),
8171
        'normal' => get_lang('PasswordNormal'),
8172
        'medium' => get_lang('PasswordMedium'),
8173
        'strong' => get_lang('PasswordStrong'),
8174
        'veryStrong' => get_lang('PasswordVeryStrong'),
8175
    ];
8176
8177
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
8178
    $js .= "<script>    
8179
    var errorMessages = {
8180
        password_to_short : \"".get_lang('PasswordIsTooShort')."\",
8181
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
8182
    };
8183
8184
    $(document).ready(function() {
8185
        var lang = ".json_encode($translations).";     
8186
        var options = {        
8187
            onLoad : function () {
8188
                //$('#messages').text('Start typing password');
8189
            },
8190
            onKeyUp: function (evt) {
8191
                $(evt.target).pwstrength('outputErrorList');
8192
            },
8193
            errorMessages : errorMessages,
8194
            viewports: {
8195
                progress: '#password_progress',
8196
                verdict: '#password-verdict',
8197
                errors: '#password-errors'
8198
            },
8199
            usernameField: '$usernameInputId'
8200
        };
8201
        options.i18n = {
8202
            t: function (key) {
8203
                var result = lang[key];
8204
                return result === key ? '' : result; // This assumes you return the                
8205
            }
8206
        };
8207
        $('".$passwordInputId."').pwstrength(options);
8208
    });
8209
    </script>";
8210
8211
    return $js;
8212
}
8213
8214
/**
8215
 * create an user extra field called 'captcha_blocked_until_date'.
8216
 *
8217
 * @param string $username
8218
 *
8219
 * @return bool
8220
 */
8221
function api_block_account_captcha($username)
8222
{
8223
    $userInfo = api_get_user_info_from_username($username);
8224
    if (empty($userInfo)) {
8225
        return false;
8226
    }
8227
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8228
    $time = time() + $minutesToBlock * 60;
8229
    UserManager::update_extra_field_value(
8230
        $userInfo['user_id'],
8231
        'captcha_blocked_until_date',
8232
        api_get_utc_datetime($time)
8233
    );
8234
8235
    return true;
8236
}
8237
8238
/**
8239
 * @param string $username
8240
 *
8241
 * @return bool
8242
 */
8243
function api_clean_account_captcha($username)
8244
{
8245
    $userInfo = api_get_user_info_from_username($username);
8246
    if (empty($userInfo)) {
8247
        return false;
8248
    }
8249
    Session::erase('loginFailedCount');
8250
    UserManager::update_extra_field_value(
8251
        $userInfo['user_id'],
8252
        'captcha_blocked_until_date',
8253
        null
8254
    );
8255
8256
    return true;
8257
}
8258
8259
/**
8260
 * @param string $username
8261
 *
8262
 * @return bool
8263
 */
8264
function api_get_user_blocked_by_captcha($username)
8265
{
8266
    $userInfo = api_get_user_info_from_username($username);
8267
    if (empty($userInfo)) {
8268
        return false;
8269
    }
8270
    $data = UserManager::get_extra_user_data_by_field(
8271
        $userInfo['user_id'],
8272
        'captcha_blocked_until_date'
8273
    );
8274
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8275
        return $data['captcha_blocked_until_date'];
8276
    }
8277
8278
    return false;
8279
}
8280
8281
/**
8282
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8283
 * Postfix the text with "..." if it has been truncated.
8284
 *
8285
 * @param string $text
8286
 * @param int    $number
8287
 *
8288
 * @return string
8289
 *
8290
 * @author hubert borderiou
8291
 */
8292
function api_get_short_text_from_html($text, $number)
8293
{
8294
    // Delete script and style tags
8295
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8296
    $text = api_html_entity_decode($text);
8297
    $out_res = api_remove_tags_with_space($text, false);
8298
    $postfix = "...";
8299
    if (strlen($out_res) > $number) {
8300
        $out_res = substr($out_res, 0, $number).$postfix;
8301
    }
8302
8303
    return $out_res;
8304
}
8305
8306
/**
8307
 * Replace tags with a space in a text.
8308
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8309
 *
8310
 * @return string
8311
 *
8312
 * @author hubert borderiou
8313
 */
8314
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8315
{
8316
    $out_res = $in_html;
8317
    if ($in_double_quote_replace) {
8318
        $out_res = str_replace('"', "''", $out_res);
8319
    }
8320
    // avoid text stuck together when tags are removed, adding a space after >
8321
    $out_res = str_replace(">", "> ", $out_res);
8322
    $out_res = strip_tags($out_res);
8323
8324
    return $out_res;
8325
}
8326
8327
/**
8328
 * If true, the drh can access all content (courses, users) inside a session.
8329
 *
8330
 * @return bool
8331
 */
8332
function api_drh_can_access_all_session_content()
8333
{
8334
    $value = api_get_setting('drh_can_access_all_session_content');
8335
8336
    return $value === 'true';
8337
}
8338
8339
/**
8340
 * @param string $tool
8341
 * @param string $setting
8342
 * @param int    $defaultValue
8343
 *
8344
 * @return string
8345
 */
8346
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8347
{
8348
    global $_configuration;
8349
    if (isset($_configuration[$tool]) &&
8350
        isset($_configuration[$tool]['default_settings']) &&
8351
        isset($_configuration[$tool]['default_settings'][$setting])
8352
    ) {
8353
        return $_configuration[$tool]['default_settings'][$setting];
8354
    }
8355
8356
    return $defaultValue;
8357
}
8358
8359
/**
8360
 * Checks if user can login as another user.
8361
 *
8362
 * @param int $loginAsUserId the user id to log in
8363
 * @param int $userId        my user id
8364
 *
8365
 * @return bool
8366
 */
8367
function api_can_login_as($loginAsUserId, $userId = null)
8368
{
8369
    if (empty($userId)) {
8370
        $userId = api_get_user_id();
8371
    }
8372
    if ($loginAsUserId == $userId) {
8373
        return false;
8374
    }
8375
8376
    if (empty($loginAsUserId)) {
8377
        return false;
8378
    }
8379
8380
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8381
        return false;
8382
    }
8383
8384
    // Check if the user to login is an admin
8385
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8386
        // Only super admins can login to admin accounts
8387
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8388
            return false;
8389
        }
8390
    }
8391
8392
    $userInfo = api_get_user_info($userId);
8393
    $isDrh = function () use ($loginAsUserId) {
8394
        if (api_is_drh()) {
8395
            if (api_drh_can_access_all_session_content()) {
8396
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8397
                    'drh_all',
8398
                    api_get_user_id()
8399
                );
8400
                $userList = [];
8401
                if (is_array($users)) {
8402
                    foreach ($users as $user) {
8403
                        $userList[] = $user['user_id'];
8404
                    }
8405
                }
8406
                if (in_array($loginAsUserId, $userList)) {
8407
                    return true;
8408
                }
8409
            } else {
8410
                if (api_is_drh() &&
8411
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8412
                ) {
8413
                    return true;
8414
                }
8415
            }
8416
        }
8417
8418
        return false;
8419
    };
8420
8421
    return api_is_platform_admin() || (api_is_session_admin() && $userInfo['status'] == 5) || $isDrh();
8422
}
8423
8424
/**
8425
 * @return bool
8426
 */
8427
function api_is_allowed_in_course()
8428
{
8429
    if (api_is_platform_admin()) {
8430
        return true;
8431
    }
8432
8433
    return Session::read('is_allowed_in_course');
8434
}
8435
8436
/**
8437
 * Set the cookie to go directly to the course code $in_firstpage
8438
 * after login.
8439
 *
8440
 * @param string $in_firstpage is the course code of the course to go
8441
 */
8442
function api_set_firstpage_parameter($in_firstpage)
0 ignored issues
show
Unused Code introduced by
The parameter $in_firstpage is not used and could be removed. ( Ignorable by Annotation )

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

8442
function api_set_firstpage_parameter(/** @scrutinizer ignore-unused */ $in_firstpage)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8443
{
8444
    //setcookie('GotoCourse', $in_firstpage);
8445
}
8446
8447
/**
8448
 * Delete the cookie to go directly to the course code $in_firstpage
8449
 * after login.
8450
 */
8451
function api_delete_firstpage_parameter()
8452
{
8453
    setcookie('GotoCourse', '', time() - 3600);
8454
}
8455
8456
/**
8457
 * @return bool if course_code for direct course access after login is set
8458
 */
8459
function exist_firstpage_parameter()
8460
{
8461
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8462
}
8463
8464
/**
8465
 * @return return the course_code of the course where user login
8466
 */
8467
function api_get_firstpage_parameter()
8468
{
8469
    return $_COOKIE['GotoCourse'];
8470
}
8471
8472
/**
8473
 * Return true on https install.
8474
 *
8475
 * @return bool
8476
 */
8477
function api_is_https()
8478
{
8479
    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...
8480
        $_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...
8481
    ) {
8482
        $isSecured = true;
8483
    } else {
8484
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8485
            $isSecured = true;
8486
        } else {
8487
            $isSecured = false;
8488
            // last chance
8489
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8490
                $isSecured = true;
8491
            }
8492
        }
8493
    }
8494
8495
    return $isSecured;
8496
}
8497
8498
/**
8499
 * Return protocol (http or https).
8500
 *
8501
 * @return string
8502
 */
8503
function api_get_protocol()
8504
{
8505
    return api_is_https() ? 'https' : 'http';
8506
}
8507
8508
/**
8509
 * Return a string where " are replaced with 2 '
8510
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8511
 * e.g. : alert("<?php get_lang('Message') ?>");
8512
 * and message contains character ".
8513
 *
8514
 * @param string $in_text
8515
 *
8516
 * @return string
8517
 */
8518
function convert_double_quote_to_single($in_text)
8519
{
8520
    return api_preg_replace('/"/', "''", $in_text);
8521
}
8522
8523
/**
8524
 * Get origin.
8525
 *
8526
 * @param string
8527
 *
8528
 * @return string
8529
 */
8530
function api_get_origin()
8531
{
8532
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8533
8534
    return $origin;
8535
}
8536
8537
/**
8538
 * Warns an user that the portal reach certain limit.
8539
 *
8540
 * @param string $limitName
8541
 */
8542
function api_warn_hosting_contact($limitName)
8543
{
8544
    $hostingParams = api_get_configuration_value(1);
8545
    $email = null;
8546
8547
    if (!empty($hostingParams)) {
8548
        if (isset($hostingParams['hosting_contact_mail'])) {
8549
            $email = $hostingParams['hosting_contact_mail'];
8550
        }
8551
    }
8552
8553
    if (!empty($email)) {
8554
        $subject = get_lang('HostingWarningReached');
8555
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8556
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8557
        if (isset($hostingParams[$limitName])) {
8558
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8559
        }
8560
        api_mail_html(null, $email, $subject, $body);
8561
    }
8562
}
8563
8564
/**
8565
 * Gets value of a variable from app/config/configuration.php
8566
 * Variables that are not set in the configuration.php file but set elsewhere:
8567
 * - virtual_css_theme_folder (vchamilo plugin)
8568
 * - access_url (global.inc.php)
8569
 * - apc/apc_prefix (global.inc.php).
8570
 *
8571
 * @param string $variable
8572
 *
8573
 * @return bool|mixed
8574
 */
8575
function api_get_configuration_value($variable)
8576
{
8577
    global $_configuration;
8578
    // Check the current url id, id = 1 by default
8579
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8580
8581
    $variable = trim($variable);
8582
8583
    // Check if variable exists
8584
    if (isset($_configuration[$variable])) {
8585
        if (is_array($_configuration[$variable])) {
8586
            // Check if it exists for the sub portal
8587
            if (array_key_exists($urlId, $_configuration[$variable])) {
8588
                return $_configuration[$variable][$urlId];
8589
            } else {
8590
                // Try to found element with id = 1 (master portal)
8591
                if (array_key_exists(1, $_configuration[$variable])) {
8592
                    return $_configuration[$variable][1];
8593
                }
8594
            }
8595
        }
8596
8597
        return $_configuration[$variable];
8598
    }
8599
8600
    return false;
8601
}
8602
8603
/**
8604
 * Returns supported image extensions in the portal.
8605
 *
8606
 * @param bool $supportVectors Whether vector images should also be accepted or not
8607
 *
8608
 * @return array Supported image extensions in the portal
8609
 */
8610
function api_get_supported_image_extensions($supportVectors = true)
8611
{
8612
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8613
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8614
    if ($supportVectors) {
8615
        array_push($supportedImageExtensions, 'svg');
8616
    }
8617
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8618
        array_push($supportedImageExtensions, 'webp');
8619
    }
8620
8621
    return $supportedImageExtensions;
8622
}
8623
8624
/**
8625
 * This setting changes the registration status for the campus.
8626
 *
8627
 * @author Patrick Cool <[email protected]>, Ghent University
8628
 *
8629
 * @version August 2006
8630
 *
8631
 * @param bool $listCampus Whether we authorize
8632
 *
8633
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8634
 */
8635
function api_register_campus($listCampus = true)
8636
{
8637
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8638
8639
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8640
    Database::query($sql);
8641
8642
    if (!$listCampus) {
8643
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8644
        Database::query($sql);
8645
    }
8646
}
8647
8648
/**
8649
 * Checks whether current user is a student boss.
8650
 *
8651
 * @global array $_user
8652
 *
8653
 * @return bool
8654
 */
8655
function api_is_student_boss()
8656
{
8657
    $_user = api_get_user_info();
8658
8659
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8660
}
8661
8662
/**
8663
 * Check whether the user type should be exclude.
8664
 * Such as invited or anonymous users.
8665
 *
8666
 * @param bool $checkDB Optional. Whether check the user status
8667
 * @param int  $userId  Options. The user id
8668
 *
8669
 * @return bool
8670
 */
8671
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8672
{
8673
    if ($checkDB) {
8674
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8675
8676
        if ($userId == 0) {
8677
            return true;
8678
        }
8679
8680
        $userInfo = api_get_user_info($userId);
8681
8682
        switch ($userInfo['status']) {
8683
            case INVITEE:
8684
            case ANONYMOUS:
8685
                return true;
8686
            default:
8687
                return false;
8688
        }
8689
    }
8690
8691
    $isInvited = api_is_invitee();
8692
    $isAnonymous = api_is_anonymous();
8693
8694
    if ($isInvited || $isAnonymous) {
8695
        return true;
8696
    }
8697
8698
    return false;
8699
}
8700
8701
/**
8702
 * Get the user status to ignore in reports.
8703
 *
8704
 * @param string $format Optional. The result type (array or string)
8705
 *
8706
 * @return array|string
8707
 */
8708
function api_get_users_status_ignored_in_reports($format = 'array')
8709
{
8710
    $excludedTypes = [
8711
        INVITEE,
8712
        ANONYMOUS,
8713
    ];
8714
8715
    if ($format == 'string') {
8716
        return implode(', ', $excludedTypes);
8717
    }
8718
8719
    return $excludedTypes;
8720
}
8721
8722
/**
8723
 * Set the Site Use Cookie Warning for 1 year.
8724
 */
8725
function api_set_site_use_cookie_warning_cookie()
8726
{
8727
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8728
}
8729
8730
/**
8731
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8732
 *
8733
 * @return bool
8734
 */
8735
function api_site_use_cookie_warning_cookie_exist()
8736
{
8737
    return isset($_COOKIE['ChamiloUsesCookies']);
8738
}
8739
8740
/**
8741
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8742
 *
8743
 * @param int    $time         The time in seconds
8744
 * @param string $originFormat Optional. PHP o JS
8745
 *
8746
 * @return string (00h00'00")
8747
 */
8748
function api_format_time($time, $originFormat = 'php')
8749
{
8750
    $h = get_lang('h');
8751
    $hours = $time / 3600;
8752
    $mins = ($time % 3600) / 60;
8753
    $secs = ($time % 60);
8754
8755
    if ($time < 0) {
8756
        $hours = 0;
8757
        $mins = 0;
8758
        $secs = 0;
8759
    }
8760
8761
    if ($originFormat == 'js') {
8762
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8763
    } else {
8764
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8765
    }
8766
8767
    return $formattedTime;
8768
}
8769
8770
/**
8771
 * Create a new empty directory with index.html file.
8772
 *
8773
 * @param string $name            The new directory name
8774
 * @param string $parentDirectory Directory parent directory name
8775
 *
8776
 * @return bool Return true if the directory was create. Otherwise return false
8777
 */
8778
function api_create_protected_dir($name, $parentDirectory)
8779
{
8780
    $isCreated = false;
8781
8782
    if (!is_writable($parentDirectory)) {
8783
        return false;
8784
    }
8785
8786
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8787
8788
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8789
        $fp = fopen($fullPath.'/index.html', 'w');
8790
8791
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource|false, thus it always evaluated to false.
Loading history...
8792
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8793
                $isCreated = true;
8794
            }
8795
        }
8796
8797
        fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

8797
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8798
    }
8799
8800
    return $isCreated;
8801
}
8802
8803
/**
8804
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
8805
 * Sender name and email can be specified, if not specified
8806
 * name and email of the platform admin are used.
8807
 *
8808
 * @author Bert Vanderkimpen ICT&O UGent
8809
 * @author Yannick Warnier <[email protected]>
8810
 *
8811
 * @param string    name of recipient
8812
 * @param string    email of recipient
8813
 * @param string    email subject
8814
 * @param string    email body
8815
 * @param string    sender name
8816
 * @param string    sender e-mail
8817
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8818
 * @param array     data file (path and filename)
8819
 * @param bool      True for attaching a embedded file inside content html (optional)
8820
 * @param array     Additional parameters
8821
 *
8822
 * @return int true if mail was sent
8823
 *
8824
 * @see             class.phpmailer.php
8825
 */
8826
function api_mail_html(
8827
    $recipient_name,
0 ignored issues
show
Unused Code introduced by
The parameter $recipient_name is not used and could be removed. ( Ignorable by Annotation )

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

8827
    /** @scrutinizer ignore-unused */ $recipient_name,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8828
    $recipient_email,
0 ignored issues
show
Unused Code introduced by
The parameter $recipient_email is not used and could be removed. ( Ignorable by Annotation )

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

8828
    /** @scrutinizer ignore-unused */ $recipient_email,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8829
    $subject,
0 ignored issues
show
Unused Code introduced by
The parameter $subject is not used and could be removed. ( Ignorable by Annotation )

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

8829
    /** @scrutinizer ignore-unused */ $subject,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8830
    $message,
0 ignored issues
show
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

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

8830
    /** @scrutinizer ignore-unused */ $message,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8831
    $senderName = '',
0 ignored issues
show
Unused Code introduced by
The parameter $senderName is not used and could be removed. ( Ignorable by Annotation )

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

8831
    /** @scrutinizer ignore-unused */ $senderName = '',

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8832
    $senderEmail = '',
0 ignored issues
show
Unused Code introduced by
The parameter $senderEmail is not used and could be removed. ( Ignorable by Annotation )

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

8832
    /** @scrutinizer ignore-unused */ $senderEmail = '',

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8833
    $extra_headers = [],
0 ignored issues
show
Unused Code introduced by
The parameter $extra_headers is not used and could be removed. ( Ignorable by Annotation )

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

8833
    /** @scrutinizer ignore-unused */ $extra_headers = [],

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8834
    $data_file = [],
0 ignored issues
show
Unused Code introduced by
The parameter $data_file is not used and could be removed. ( Ignorable by Annotation )

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

8834
    /** @scrutinizer ignore-unused */ $data_file = [],

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8835
    $embedded_image = false,
0 ignored issues
show
Unused Code introduced by
The parameter $embedded_image is not used and could be removed. ( Ignorable by Annotation )

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

8835
    /** @scrutinizer ignore-unused */ $embedded_image = false,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8836
    $additionalParameters = []
0 ignored issues
show
Unused Code introduced by
The parameter $additionalParameters is not used and could be removed. ( Ignorable by Annotation )

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

8836
    /** @scrutinizer ignore-unused */ $additionalParameters = []

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8837
) {
8838
    global $platform_email;
8839
8840
    return;
8841
8842
    $mail = new PHPMailer();
0 ignored issues
show
Unused Code introduced by
$mail = new PHPMailer() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
8843
    $mail->Mailer = $platform_email['SMTP_MAILER'];
8844
    $mail->Host = $platform_email['SMTP_HOST'];
8845
    $mail->Port = $platform_email['SMTP_PORT'];
8846
    $mail->CharSet = $platform_email['SMTP_CHARSET'];
8847
    // Stay far below SMTP protocol 980 chars limit.
8848
    $mail->WordWrap = 200;
8849
8850
    if ($platform_email['SMTP_AUTH']) {
8851
        $mail->SMTPAuth = 1;
8852
        $mail->Username = $platform_email['SMTP_USER'];
8853
        $mail->Password = $platform_email['SMTP_PASS'];
8854
        if (isset($platform_email['SMTP_SECURE'])) {
8855
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
8856
        }
8857
    }
8858
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
8859
8860
    // 5 = low, 1 = high
8861
    $mail->Priority = 3;
8862
    $mail->SMTPKeepAlive = true;
8863
8864
    // Default values
8865
    $notification = new Notification();
8866
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8867
    $defaultName = $notification->getDefaultPlatformSenderName();
8868
8869
    // If the parameter is set don't use the admin.
8870
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8871
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8872
8873
    // Reply to first
8874
    if (isset($extra_headers['reply_to']) && empty($platform_email['SMTP_UNIQUE_REPLY_TO'])) {
8875
        $mail->AddReplyTo(
8876
            $extra_headers['reply_to']['mail'],
8877
            $extra_headers['reply_to']['name']
8878
        );
8879
        // Errors to sender
8880
        $mail->AddCustomHeader('Errors-To: '.$extra_headers['reply_to']['mail']);
8881
        $mail->Sender = $extra_headers['reply_to']['mail'];
8882
        unset($extra_headers['reply_to']);
8883
    } else {
8884
        $mail->AddCustomHeader('Errors-To: '.$defaultEmail);
8885
    }
8886
8887
    //If the SMTP configuration only accept one sender
8888
    if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8889
        $senderName = $platform_email['SMTP_FROM_NAME'];
8890
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8891
        $valid = PHPMailer::validateAddress($senderEmail);
8892
        if ($valid) {
8893
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8894
            $mail->Sender = $senderEmail;
8895
        }
8896
    }
8897
8898
    $mail->SetFrom($senderEmail, $senderName);
8899
    $mail->Subject = $subject;
8900
    $mail->AltBody = strip_tags(
8901
        str_replace('<br />', "\n", api_html_entity_decode($message))
8902
    );
8903
8904
    $list = api_get_configuration_value('send_all_emails_to');
8905
    if (!empty($list) && isset($list['emails'])) {
8906
        foreach ($list['emails'] as $email) {
8907
            //$mail->AddBCC($email);
8908
            $mail->AddAddress($email);
8909
        }
8910
    }
8911
8912
    // Send embedded image.
8913
    if ($embedded_image) {
8914
        // Get all images html inside content.
8915
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
8916
        // Prepare new tag images.
8917
        $new_images_html = [];
8918
        $i = 1;
8919
        if (!empty($m[1])) {
8920
            foreach ($m[1] as $image_path) {
8921
                $real_path = realpath($image_path);
8922
                $filename = basename($image_path);
8923
                $image_cid = $filename.'_'.$i;
8924
                $encoding = 'base64';
8925
                $image_type = mime_content_type($real_path);
8926
                $mail->AddEmbeddedImage(
8927
                    $real_path,
8928
                    $image_cid,
8929
                    $filename,
8930
                    $encoding,
8931
                    $image_type
8932
                );
8933
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
8934
                $i++;
8935
            }
8936
        }
8937
8938
        // Replace origin image for new embedded image html.
8939
        $x = 0;
8940
        if (!empty($m[0])) {
8941
            foreach ($m[0] as $orig_img) {
8942
                $message = str_replace($orig_img, $new_images_html[$x], $message);
8943
                $x++;
8944
            }
8945
        }
8946
    }
8947
8948
    $mailView = new Template(null, false, false, false, false, false, false);
8949
8950
    $noReply = api_get_setting('noreply_email_address');
8951
    if (!empty($noReply)) {
8952
        $message .= "<br />".get_lang('ThisIsAutomaticEmailNoReply');
8953
    }
8954
    $mailView->assign('content', $message);
8955
8956
    if (isset($additionalParameters['link'])) {
8957
        $mailView->assign('link', $additionalParameters['link']);
8958
    }
8959
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
8960
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
8961
    $layout = $mailView->get_template('mail/mail.tpl');
8962
    $mail->Body = $mailView->fetch($layout);
8963
8964
    // Attachment ...
8965
    if (!empty($data_file)) {
8966
        foreach ($data_file as $file_attach) {
8967
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8968
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
8969
            }
8970
        }
8971
    }
8972
8973
    // Only valid addresses are accepted.
8974
    if (is_array($recipient_email)) {
8975
        foreach ($recipient_email as $dest) {
8976
            if (api_valid_email($dest)) {
8977
                $mail->AddAddress($dest, $recipient_name);
8978
            }
8979
        }
8980
    } else {
8981
        if (api_valid_email($recipient_email)) {
8982
            $mail->AddAddress($recipient_email, $recipient_name);
8983
        } else {
8984
            return 0;
8985
        }
8986
    }
8987
8988
    if (is_array($extra_headers) && count($extra_headers) > 0) {
8989
        foreach ($extra_headers as $key => $value) {
8990
            switch (strtolower($key)) {
8991
                case 'encoding':
8992
                case 'content-transfer-encoding':
8993
                    $mail->Encoding = $value;
8994
                    break;
8995
                case 'charset':
8996
                    $mail->Charset = $value;
8997
                    break;
8998
                case 'contenttype':
8999
                case 'content-type':
9000
                    $mail->ContentType = $value;
9001
                    break;
9002
                default:
9003
                    $mail->AddCustomHeader($key.':'.$value);
9004
                    break;
9005
            }
9006
        }
9007
    } else {
9008
        if (!empty($extra_headers)) {
9009
            $mail->AddCustomHeader($extra_headers);
9010
        }
9011
    }
9012
9013
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
9014
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
9015
9016
    // Send the mail message.
9017
    if (!$mail->Send()) {
9018
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
9019
        if ($mail->SMTPDebug) {
9020
            error_log(
9021
                "Connection details :: ".
9022
                "Protocol: ".$mail->Mailer.' :: '.
9023
                "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
9024
                "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
9025
                ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
9026
                "Sender: ".$mail->Sender
9027
            );
9028
        }
9029
9030
        return 0;
9031
    }
9032
9033
    if (!empty($additionalParameters)) {
9034
        $plugin = new AppPlugin();
9035
        $smsPlugin = $plugin->getSMSPluginLibrary();
9036
        if ($smsPlugin) {
9037
            $smsPlugin->send($additionalParameters);
9038
        }
9039
    }
9040
9041
    // Clear all the addresses.
9042
    $mail->ClearAddresses();
9043
9044
    // Clear all attachments
9045
    $mail->ClearAttachments();
9046
9047
    return 1;
9048
}
9049
9050
/**
9051
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
9052
 * @param bool   $showHeader
9053
 */
9054
function api_protect_course_group($tool, $showHeader = true)
9055
{
9056
    $userId = api_get_user_id();
9057
    $groupId = api_get_group_id();
9058
    $groupInfo = GroupManager::get_group_properties($groupId);
9059
9060
    if (!empty($groupInfo)) {
9061
        $allow = GroupManager::user_has_access(
9062
            $userId,
9063
            $groupInfo['iid'],
9064
            $tool
9065
        );
9066
9067
        if (!$allow) {
9068
            api_not_allowed($showHeader);
9069
        }
9070
    }
9071
}
9072
9073
/**
9074
 * Check if a date is in a date range.
9075
 *
9076
 * @param datetime $startDate
9077
 * @param datetime $endDate
9078
 * @param datetime $currentDate
9079
 *
9080
 * @return bool true if date is in rage, false otherwise
9081
 */
9082
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9083
{
9084
    $startDate = strtotime(api_get_local_time($startDate));
9085
    $endDate = strtotime(api_get_local_time($endDate));
9086
    $currentDate = strtotime(api_get_local_time($currentDate));
9087
9088
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9089
        return true;
9090
    }
9091
9092
    return false;
9093
}
9094
9095
/**
9096
 * Eliminate the duplicates of a multidimensional array by sending the key.
9097
 *
9098
 * @param array $array multidimensional array
9099
 * @param int   $key   key to find to compare
9100
 *
9101
 * @return array
9102
 */
9103
function api_unique_multidim_array($array, $key)
9104
{
9105
    $temp_array = [];
9106
    $i = 0;
9107
    $key_array = [];
9108
9109
    foreach ($array as $val) {
9110
        if (!in_array($val[$key], $key_array)) {
9111
            $key_array[$i] = $val[$key];
9112
            $temp_array[$i] = $val;
9113
        }
9114
        $i++;
9115
    }
9116
9117
    return $temp_array;
9118
}
9119
9120
/**
9121
 * Limit the access to Session Admins when the limit_session_admin_role
9122
 * configuration variable is set to true.
9123
 */
9124
function api_protect_limit_for_session_admin()
9125
{
9126
    $limitAdmin = api_get_setting('limit_session_admin_role');
9127
    if (api_is_session_admin() && $limitAdmin === 'true') {
9128
        api_not_allowed(true);
9129
    }
9130
}
9131
9132
/**
9133
 * @return bool
9134
 */
9135
function api_is_student_view_active()
9136
{
9137
    $studentView = Session::read('studentview');
9138
9139
    return $studentView == 'studentview';
9140
}
9141
9142
/**
9143
 * Adds a file inside the upload/$type/id.
9144
 *
9145
 * @param string $type
9146
 * @param array  $file
9147
 * @param int    $itemId
9148
 * @param string $cropParameters
9149
 *
9150
 * @return array|bool
9151
 */
9152
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9153
{
9154
    $upload = process_uploaded_file($file);
9155
    if ($upload) {
9156
        $name = api_replace_dangerous_char($file['name']);
9157
9158
        // No "dangerous" files
9159
        $name = disable_dangerous_file($name);
9160
9161
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9162
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9163
9164
        if (!is_dir($path)) {
9165
            mkdir($path, api_get_permissions_for_new_directories(), true);
9166
        }
9167
9168
        $pathToSave = $path.$name;
9169
        $result = moveUploadedFile($file, $pathToSave);
9170
9171
        if ($result) {
9172
            if (!empty($cropParameters)) {
9173
                $image = new Image($pathToSave);
9174
                $image->crop($cropParameters);
9175
            }
9176
9177
            return ['path_to_save' => $pathId.$name];
9178
        }
9179
9180
        return false;
9181
    }
9182
}
9183
9184
/**
9185
 * @param string $type
9186
 * @param int    $itemId
9187
 * @param string $file
9188
 *
9189
 * @return bool
9190
 */
9191
function api_get_uploaded_web_url($type, $itemId, $file)
9192
{
9193
    return api_get_uploaded_file($type, $itemId, $file, true);
9194
}
9195
9196
/**
9197
 * @param string $type
9198
 * @param int    $itemId
9199
 * @param string $file
9200
 * @param bool   $getUrl
9201
 *
9202
 * @return bool
9203
 */
9204
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9205
{
9206
    $itemId = (int) $itemId;
9207
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9208
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9209
    $file = basename($file);
9210
    $file = $path.'/'.$file;
9211
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9212
        if ($getUrl) {
9213
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
0 ignored issues
show
Bug Best Practice introduced by
The expression return str_replace(api_g...EB_UPLOAD_PATH), $file) returns the type string which is incompatible with the documented return type boolean.
Loading history...
9214
        }
9215
9216
        return $file;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $file returns the type string which is incompatible with the documented return type boolean.
Loading history...
9217
    }
9218
9219
    return false;
9220
}
9221
9222
/**
9223
 * @param string $type
9224
 * @param int    $itemId
9225
 * @param string $file
9226
 * @param string $title
9227
 */
9228
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9229
{
9230
    $file = api_get_uploaded_file($type, $itemId, $file);
9231
    if ($file) {
9232
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9233
            DocumentManager::file_send_for_download($file, true, $title);
9234
            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...
9235
        }
9236
    }
9237
    api_not_allowed(true);
9238
}
9239
9240
/**
9241
 * @param string $type
9242
 * @param string $file
9243
 */
9244
function api_remove_uploaded_file($type, $file)
9245
{
9246
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9247
    $path = $typePath.'/'.$file;
9248
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9249
        unlink($path);
9250
    }
9251
}
9252
9253
/**
9254
 * @param string $type
9255
 * @param int    $itemId
9256
 * @param string $file
9257
 *
9258
 * @return bool
9259
 */
9260
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9261
{
9262
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9263
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9264
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9265
        unlink($file);
9266
9267
        return true;
9268
    }
9269
9270
    return false;
9271
}
9272
9273
/**
9274
 * Converts string value to float value.
9275
 *
9276
 * 3.141516 => 3.141516
9277
 * 3,141516 => 3.141516
9278
 *
9279
 * @todo WIP
9280
 *
9281
 * @param string $number
9282
 *
9283
 * @return float
9284
 */
9285
function api_float_val($number)
9286
{
9287
    $number = (float) str_replace(',', '.', trim($number));
9288
9289
    return $number;
9290
}
9291
9292
/**
9293
 * Converts float values
9294
 * Example if $decimals = 2.
9295
 *
9296
 * 3.141516 => 3.14
9297
 * 3,141516 => 3,14
9298
 *
9299
 * @param string $number            number in iso code
9300
 * @param int    $decimals
9301
 * @param string $decimalSeparator
9302
 * @param string $thousandSeparator
9303
 *
9304
 * @return bool|string
9305
 */
9306
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9307
{
9308
    $number = api_float_val($number);
9309
9310
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9311
}
9312
9313
/**
9314
 * Set location url with a exit break by default.
9315
 *
9316
 * @param $url
9317
 * @param bool $exit
9318
 */
9319
function location($url, $exit = true)
9320
{
9321
    header('Location: '.$url);
9322
9323
    if ($exit) {
9324
        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...
9325
    }
9326
}
9327
9328
/**
9329
 * @return string
9330
 */
9331
function api_get_web_url()
9332
{
9333
    if (api_get_setting('server_type') === 'test') {
9334
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9335
    } else {
9336
        return api_get_path(WEB_PATH).'web/';
9337
    }
9338
}
9339
9340
/**
9341
 * @param string $from
9342
 * @param string $to
9343
 *
9344
 * @return string
9345
 */
9346
function api_get_relative_path($from, $to)
9347
{
9348
    // some compatibility fixes for Windows paths
9349
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9350
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9351
    $from = str_replace('\\', '/', $from);
9352
    $to = str_replace('\\', '/', $to);
9353
9354
    $from = explode('/', $from);
9355
    $to = explode('/', $to);
9356
    $relPath = $to;
9357
9358
    foreach ($from as $depth => $dir) {
9359
        // find first non-matching dir
9360
        if ($dir === $to[$depth]) {
9361
            // ignore this directory
9362
            array_shift($relPath);
9363
        } else {
9364
            // get number of remaining dirs to $from
9365
            $remaining = count($from) - $depth;
9366
            if ($remaining > 1) {
9367
                // add traversals up to first matching dir
9368
                $padLength = (count($relPath) + $remaining - 1) * -1;
9369
                $relPath = array_pad($relPath, $padLength, '..');
9370
                break;
9371
            } else {
9372
                $relPath[0] = './'.$relPath[0];
9373
            }
9374
        }
9375
    }
9376
9377
    return implode('/', $relPath);
9378
}
9379